Skip to content

Commit 15f181c

Browse files
authored
Merge pull request #347 from k01zero/part2-김경린
[김경린] sprint 7
2 parents 649d69a + 04a5133 commit 15f181c

File tree

117 files changed

+7887
-624
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

117 files changed

+7887
-624
lines changed

.github/img_4.png

138 KB
Loading

.github/pull-request-template.md

+179-223
Large diffs are not rendered by default.

.logs/app.2025-03-28.log

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
25-03-28 14:34:43.799 [main] INFO c.s.m.discodeit.DiscodeitApplication - Starting DiscodeitApplication using Java 17.0.12 with PID 70960 (C:\Users\User\OneDrive\Desktop\codeit\1-sprint-mission\build\classes\java\main started by User in C:\Users\User\OneDrive\Desktop\codeit\1-sprint-mission)
2+
25-03-28 14:34:43.801 [main] INFO c.s.m.discodeit.DiscodeitApplication - The following 1 profile is active: "prod"
3+
25-03-28 14:34:46.614 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in DEFAULT mode.
4+
25-03-28 14:34:46.798 [main] INFO o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 169 ms. Found 6 JPA repository interfaces.
5+
25-03-28 14:34:48.014 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port 8080 (http)
6+
25-03-28 14:34:48.036 [main] INFO o.a.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-8080"]
7+
25-03-28 14:34:48.041 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat]
8+
25-03-28 14:34:48.041 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.33]
9+
25-03-28 14:34:48.201 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
10+
25-03-28 14:34:48.202 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 4324 ms
11+
25-03-28 14:34:48.448 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
12+
25-03-28 14:34:48.946 [main] INFO com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection org.postgresql.jdbc.PgConnection@2fdf22f7
13+
25-03-28 14:34:48.950 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
14+
25-03-28 14:34:49.192 [main] INFO o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
15+
25-03-28 14:34:49.360 [main] INFO org.hibernate.Version - HHH000412: Hibernate ORM core version 6.5.3.Final
16+
25-03-28 14:34:49.449 [main] INFO o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
17+
25-03-28 14:34:50.179 [main] INFO o.s.o.j.p.SpringPersistenceUnitInfo - No LoadTimeWeaver setup: ignoring JPA class transformer
18+
25-03-28 14:34:52.324 [main] INFO o.h.e.t.j.p.i.JtaPlatformInitiator - HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
19+
25-03-28 14:34:52.476 [main] INFO o.s.o.j.LocalContainerEntityManagerFactoryBean - Initialized JPA EntityManagerFactory for persistence unit 'default'
20+
25-03-28 14:34:53.625 [main] WARN o.s.b.a.o.j.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
21+
25-03-28 14:34:53.656 [main] INFO o.s.b.a.w.s.WelcomePageHandlerMapping - Adding welcome page: class path resource [static/index.html]
22+
25-03-28 14:34:55.632 [main] INFO o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-8080"]
23+
25-03-28 14:34:55.678 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port 8080 (http) with context path '/'
24+
25-03-28 14:34:55.697 [main] INFO c.s.m.discodeit.DiscodeitApplication - Started DiscodeitApplication in 12.781 seconds (process running for 21.381)
25+
25-03-28 14:35:23.964 [http-nio-8080-exec-1] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet'
26+
25-03-28 14:35:23.964 [http-nio-8080-exec-1] INFO o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
27+
25-03-28 14:35:23.967 [http-nio-8080-exec-1] INFO o.s.web.servlet.DispatcherServlet - Completed initialization in 2 ms
28+
25-03-28 14:35:26.004 [http-nio-8080-exec-2] INFO o.s.api.AbstractOpenApiResource - Init duration for springdoc-openapi is: 1115 ms
29+
25-03-28 14:44:14.631 [SpringApplicationShutdownHook] INFO o.s.o.j.LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'default'
30+
25-03-28 14:44:14.633 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated...
31+
25-03-28 14:44:14.642 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed.

.logs/app.2025-03-30.log

+268
Large diffs are not rendered by default.

.logs/app.2025-03-31.log

+225
Large diffs are not rendered by default.

.logs/app.2025-04-01.log

+2,383
Large diffs are not rendered by default.

.logs/app.log

+1,429
Large diffs are not rendered by default.

build.gradle

+30-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ plugins {
33
id 'application' // application 플러그인 추가
44
id 'org.springframework.boot' version '3.3.6'
55
id 'io.spring.dependency-management' version '1.1.7'
6+
id 'com.gorylenko.gradle-git-properties' version '2.4.1' // git 정보 읽기
67
}
78

89
group = 'com.sprint.mission'
@@ -39,6 +40,12 @@ dependencies {
3940
// Spring Boot Web 의존성 (Spring MVC, REST 등)
4041
implementation 'org.springframework.boot:spring-boot-starter-web'
4142

43+
// Spring Validation 의존성
44+
implementation 'org.springframework.boot:spring-boot-starter-validation'
45+
46+
// Spring Actuator 의존성
47+
implementation 'org.springframework.boot:spring-boot-starter-actuator'
48+
4249
// Lombok 의존성 (간결한 코드 작성)
4350
compileOnly 'org.projectlombok:lombok' // 컴파일 타임에만 Lombok을 사용
4451
annotationProcessor 'org.projectlombok:lombok' // Lombok 애노테이션 프로세서
@@ -49,9 +56,14 @@ dependencies {
4956

5057
// PostgreSQL 의존성
5158
runtimeOnly 'org.postgresql:postgresql' // 런타임에만 PostgreSQL 드라이버
59+
// h2 의존성
60+
runtimeOnly 'com.h2database:h2'
5261

5362
// Spring Boot Test 의존성
54-
testImplementation 'org.springframework.boot:spring-boot-starter-test' // 테스트 관련 의존성
63+
testImplementation 'org.springframework.boot:spring-boot-starter-test'
64+
65+
// Mockito 의존성
66+
implementation "org.mockito:mockito-core:4.6.1"
5567

5668
// JUnit 플랫폼 런처 (JUnit 테스트 실행)
5769
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
@@ -61,6 +73,23 @@ dependencies {
6173
}
6274

6375

76+
gitProperties {
77+
dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
78+
dateFormatTimeZone = "UTC"
79+
}
80+
81+
tasks.register('writeBuildProperties') {
82+
doLast {
83+
def props = new Properties()
84+
props.setProperty('version', project.version.toString())
85+
props.setProperty('time', new Date().format("yyyy-MM-dd'T' HH:mm:ss'Z'", Timezone.getTimeZone("UTC")))
86+
87+
def file = file("$buildDir/resources/main/build.properties")
88+
file.parentFile.mkdir()
89+
props.store(file.newWriter(), null)
90+
}
91+
}
92+
6493
tasks.named('test') {
6594
useJUnitPlatform()
6695
}

error-log/DB연결 오류.md

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
문제 상황 :
2+
3+
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean
4+
with name 'dataSourceScriptDatabaseInitializer' defined in class path
5+
resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]:
6+
Unsatisfied dependency expressed through method 'dataSourceScriptDatabaseInitializer' parameter 0:
7+
Error creating bean with name 'dataSource' defined in class path
8+
resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Failed
9+
to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception
10+
with message: Failed to load driver class org.h2.Driver in either of HikariConfig class loader or
11+
Thread context classloader
12+
13+
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean
14+
with name 'dataSourceScriptDatabaseInitializer' defined in class path
15+
16+
클래스 경로에 'dataSourceScriptDatabaseInitializer'라는 이름으로 정의된 빈을 생성할 수 없는 오류가 발생했다.
17+
UnsatisfiedDependencyException = 불만족스러운 종속성 예외
18+
19+
Failed to load driver class org.h2.Driver in either of HikariConfig class loader or
20+
Thread context classloader
21+
H2 드라이버(org.h2.Driver)를 로드할 수 없다.
22+
23+
해결 : 의존성 추가, 설정 파일에 설정 추가
24+
25+
1. 의존성 추가
26+
![img_1.png](img_1.png)
27+
28+
새로운 의존성을 추가한 후 다운로드할 수 있게 build.gradle 을 통해 org.h2.Driver 클래스가 인식되도록 했다.
29+
30+
2. yml 설정 파일에 설정 추가
31+
![img_2.png](img_2.png)
32+
33+
공통 설정 파일에 spring:profiles:active: dev, datasource:driver-class-name: org.h2.Driver 를 설정했다.
34+
35+
![img_3.png](img_3.png)
36+
37+
38+
-----
39+
40+
문제 상황2 :
41+
42+
2025-03-27T16:14:02.827+09:00 ERROR 18156 --- [discodeit] [ main]
43+
j.LocalContainerEntityManagerFactoryBean : Failed to initialize JPA
44+
EntityManagerFactory: [PersistenceUnit: default] Unable to build Hibernate SessionFactory; nested
45+
exception is org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: missing
46+
table [message]
47+
2025-03-27T16:14:02.830+09:00 WARN 18156 --- [discodeit] [ main]
48+
ConfigServletWebServerApplicationContext : Exception encountered during context initialization -
49+
cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating
50+
bean with name 'entityManagerFactory' defined in class path
51+
resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: [PersistenceUnit: default]
52+
Unable to build Hibernate SessionFactory; nested exception is
53+
org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: missing table [message]
54+
55+
Schema-validation: missing table [message]
56+
스키마 검증 단계에서 message 라는 테이블이 없어서 발생한 문제이다.
57+
58+
해결 : H2 DB에 테이블 생성
59+
60+
DB에 message 테이블이 없거나, 아예 테이블을 생성하는 SQL(schema.sql)이 실행되지 않았거나 둘 중 하나라고 생각했다.
61+
때문에 H2 DB에 데이터테이블을 생성하는 방법을 찾자, 두 가지 방법이 나왔다.
62+
63+
1. 스프링 부트의 DB 테이블 만들기
64+
- spring.sql.init.mode 사용
65+
2. 하이버네이트가 테이블을 자동 생성해주기
66+
- jpa:hibernate:ddl-auto : 를 create, update 로 지정
67+
68+
이때, 이 두가지 설정을 동시에 이용하면 안 된다. 스프링 부트에서 테이블을 생성하려고 하는 동작과 하이버네이트가 자동 테이블을 자동 생성하려는 동작에 충돌이 있다.
69+
![img_6.png](img_6.png)
70+
실제로 jpa:hibernate:ddl-auto를 validation으로 지정한 후 테이블을 생성하려고 하자, 여전히 message 테이블이 존재하지 않는다는 오류가 동일하게
71+
떴다.
72+
이후 jpa:hibernate:ddl-auto를 none으로 설정하자, 애플리케이션이 실행될 수 있었다.
73+
74+
[[Spring Boot] DB Schema 및 Data 초기화 schema.sql data.sql
75+
](https://chaewsscode.tistory.com/174)
76+
[[Spring] org.springframework.beans.factory.UnsatisfiedDependencyException 에러](https://yn98.tistory.com/84#%EC%A3%BC%EC%9A%94%20%EC%9B%90%EC%9D%B8-1)
77+
[SQL 데이터베이스](https://docs.spring.io/spring-boot/reference/data/sql.html#data.sql.h2-web-console)

error-log/img_1.png

39.2 KB
Loading

error-log/img_2.png

16.3 KB
Loading

error-log/img_3.png

107 KB
Loading

error-log/img_6.png

48.6 KB
Loading

error-log/img_7.png

274 KB
Loading
+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
### 문제 상황 :
2+
3+
Strict stubbing argument mismatch. Please check:
4+
5+
- this invocation of 'toDto' method:
6+
userMapper.toDto(
7+
com.sprint.mission.discodeit.entity.User@743c6ce4
8+
);
9+
-> at com.sprint.mission.discodeit.service.basic.BasicUserService.createUser(
10+
BasicUserService.java:92)
11+
- has following stubbing(s) with different arguments:
12+
1. userMapper.toDto(
13+
com.sprint.mission.discodeit.entity.User@30669dac
14+
);
15+
-> at com.sprint.mission.discodeit.service.UserServiceTest.createUser_Success(
16+
UserServiceTest.java:77)
17+
Typically, stubbing argument mismatch indicates user mistake when writing tests.
18+
Mockito fails early so that you can debug potential problem easily.
19+
However, there are legit scenarios when this exception generates false negative signal:
20+
- stubbing the same method multiple times using 'given().will()' or 'when().then()' API
21+
Please use 'will().given()' or 'doReturn().when()' API for stubbing.
22+
- stubbed method is intentionally invoked with different arguments by code under test
23+
Please use default or 'silent' JUnit Rule (equivalent of Strictness.LENIENT).
24+
For more information see javadoc for PotentialStubbingProblem class.
25+
org.mockito.exceptions.misusing.PotentialStubbingProblem:
26+
Strict stubbing argument mismatch. Please check:
27+
- this invocation of 'toDto' method:
28+
userMapper.toDto(
29+
com.sprint.mission.discodeit.entity.User@743c6ce4
30+
);
31+
32+
### 문제가 일어난 이유 : User 객체가 테스트 코드에서 예상한 것과 다른 인수로 호출됐다.
33+
34+
Strict stubbing argument mismatch. Please check:
35+
Strict stubbing argument mismatch. Please check:
36+
37+
- this invocation of 'toDto' method:
38+
userMapper.toDto(
39+
com.sprint.mission.discodeit.entity.User@743c6ce4
40+
);
41+
-> at com.sprint.mission.discodeit.service.basic.BasicUserService.createUser(
42+
BasicUserService.java:92)
43+
- has following stubbing(s) with different arguments:
44+
1. userMapper.toDto(
45+
com.sprint.mission.discodeit.entity.User@30669dac
46+
);
47+
-> at com.sprint.mission.discodeit.service.UserServiceTest.createUser_Success(
48+
UserServiceTest.java:77)
49+
50+
실제로 호출된 userMapper.toDto() 메서드는 com.sprint.mission.discodeit.entity.User@743c6ce4 객체를 인자로 받았지만,
51+
테스트에서 stubbing한 호출은 com.sprint.mission.discodeit.entity.User@30669dac 객체를 인자로 기대했습니다.
52+
53+
테스트에서 생성된 user 객체와 BasicUserService.createUser() 메서드 내부에서 생성되는 User 객체가 서로 다른 인스턴스이기 때문에 발생한 문제입니다.
54+
55+
### 해결 : user 객체가 expected 값과 동일한 값으로 stub될 수 있도록 설정해야 한다.
56+
57+
user 을 전달받던 userMapper.toDto() 메서드에 `any(User.class)` 를 전달한다.
58+
테스트 의의에 맞게 변경했다.
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
### 상황 :
2+
3+
![img_7.png](img_7.png)
4+
jakarta.validation.UnexpectedTypeException: HV000030: 'jakarta.validation.constraints.NotBlank' 제약
5+
조건에 대한 유효성 검사기를 찾을 수 없습니다. 'java.util.UUID' 유형을 유효성 검사합니다. 'authorId'에 대한 구성을 확인합니다
6+
7+
### 문제가 일어난 이유 : @NotBlank 제약 조건은 문자열(String) 유형에 적용해야 한다.
8+
9+
UUID 유형에 @NotBlank 제약 조건을 걸어놔 발생한 문제였다.
10+
11+
### 해결 : @NotBlank -> @NotNull

src/main/java/com/sprint/mission/discodeit/DiscodeitApplication.java

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
66

77
@SpringBootApplication
8-
@EnableJpaAuditing
98
public class DiscodeitApplication {
109

1110
public static void main(String[] args) {

src/main/java/com/sprint/mission/discodeit/config/AppConfig.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
public class AppConfig {
1111

1212
@Bean
13-
@ConditionalOnProperty(name = "discodeit.stroage.type", havingValue = "local")
13+
@ConditionalOnProperty(name = "discodeit.storage.type", havingValue = "local")
1414
public BinaryContentStorage binaryContentStorage() {
1515
return new LocalBinaryContentStorage();
1616
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.sprint.mission.discodeit.config;
2+
3+
import org.springframework.context.annotation.Configuration;
4+
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
5+
6+
@Configuration
7+
@EnableJpaAuditing // @WebMvcTest 와의 충돌을 고려해 분리
8+
public class JpaConfig {
9+
10+
}

src/main/java/com/sprint/mission/discodeit/controller/AuthController.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.sprint.mission.discodeit.controller;
22

3+
import com.sprint.mission.discodeit.controller.api.AuthApi;
34
import com.sprint.mission.discodeit.dto.user.UserLoginRequest;
45
import com.sprint.mission.discodeit.entity.User;
56
import com.sprint.mission.discodeit.service.basic.AuthService;
@@ -13,7 +14,7 @@
1314
@RestController
1415
@RequestMapping("/api/auth")
1516
@RequiredArgsConstructor
16-
public class AuthController {
17+
public class AuthController implements AuthApi {
1718

1819
private final AuthService authService;
1920

src/main/java/com/sprint/mission/discodeit/controller/BinaryFileController.java

+8-6
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
import com.sprint.mission.discodeit.service.BinaryContentService;
66
import com.sprint.mission.discodeit.storage.BinaryContentStorage;
77
import lombok.RequiredArgsConstructor;
8+
import lombok.extern.slf4j.Slf4j;
9+
import org.springframework.http.HttpStatus;
810
import org.springframework.http.ResponseEntity;
911
import org.springframework.web.bind.annotation.*;
1012

1113
import java.util.List;
1214
import java.util.UUID;
1315

16+
@Slf4j
1417
@RestController
1518
@RequestMapping("/api/binaryContents")
1619
@RequiredArgsConstructor
@@ -26,12 +29,11 @@ public ResponseEntity<BinaryContentDto> binaryContentFindById(
2629

2730
@GetMapping(value = "/{binaryContentId}/download")
2831
public ResponseEntity<?> downloadBinaryContent(@PathVariable UUID id) {
29-
// BinaryContentStorage 를 직접 들고와서 쓰라는 것(클래스 다이어그램)으로 이해는 했지만,
30-
// 그러면 컨트롤러 단에서 Mapper를 통한 변환(id로 BinaryContent 를 부르고, BinaryContent <-> DTO)이 이뤄이지 때문에
31-
// 저는 우선 binaryContentService 에 download 관련 메서드를 추가했습니다.
32-
// 내부적으로는 binaryContentStorage 의 downlaod 메서드가 호출됩니다.
33-
// 즉, 다운로드 API -> (컨트롤러 - 서비스 - 스토리지) 단에서 기능 구현
34-
return binaryContentService.downloadBinaryContent(id);
32+
log.info("파일 다운로드 요청(Request)");
33+
34+
ResponseEntity<?> downloadBinaryContent = binaryContentService.downloadBinaryContent(id);
35+
log.info("파일 다운로드 응답(Response): HttpStatus={}", HttpStatus.OK);
36+
return downloadBinaryContent;
3537
}
3638

3739
@GetMapping

0 commit comments

Comments
 (0)