From 907fa905a2fbefa310635ce6788b3271ffc36a11 Mon Sep 17 00:00:00 2001 From: bsh-ko Date: Mon, 9 Mar 2026 19:46:11 +0900 Subject: [PATCH 01/11] =?UTF-8?q?feat:=20=EA=B3=B5=ED=86=B5=20=EC=9D=91?= =?UTF-8?q?=EB=8B=B5=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/PingController.java | 6 ++- .../global/apiPayload/ApiResponse.java | 38 +++++++++++++++++++ .../global/apiPayload/code/BaseErrorCode.java | 9 +++++ .../apiPayload/code/BaseSuccessCode.java | 9 +++++ .../apiPayload/code/GeneralErrorCode.java | 28 ++++++++++++++ .../apiPayload/code/GeneralSuccessCode.java | 15 ++++++++ src/main/resources/application.properties | 1 - src/main/resources/application.yml | 19 ++++++++++ 8 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/study/spring1team/global/apiPayload/ApiResponse.java create mode 100644 src/main/java/com/study/spring1team/global/apiPayload/code/BaseErrorCode.java create mode 100644 src/main/java/com/study/spring1team/global/apiPayload/code/BaseSuccessCode.java create mode 100644 src/main/java/com/study/spring1team/global/apiPayload/code/GeneralErrorCode.java create mode 100644 src/main/java/com/study/spring1team/global/apiPayload/code/GeneralSuccessCode.java delete mode 100644 src/main/resources/application.properties create mode 100644 src/main/resources/application.yml diff --git a/src/main/java/com/study/spring1team/controller/PingController.java b/src/main/java/com/study/spring1team/controller/PingController.java index ce95df7..a11be03 100644 --- a/src/main/java/com/study/spring1team/controller/PingController.java +++ b/src/main/java/com/study/spring1team/controller/PingController.java @@ -1,5 +1,7 @@ package com.study.spring1team.controller; +import com.study.spring1team.global.apiPayload.ApiResponse; +import com.study.spring1team.global.apiPayload.code.GeneralSuccessCode; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -9,7 +11,7 @@ public class PingController { @GetMapping("/ping") - public String ping() { - return "pong"; + public ApiResponse ping() { + return ApiResponse.onSuccess(GeneralSuccessCode.OK,"pong"); } } \ No newline at end of file diff --git a/src/main/java/com/study/spring1team/global/apiPayload/ApiResponse.java b/src/main/java/com/study/spring1team/global/apiPayload/ApiResponse.java new file mode 100644 index 0000000..365975c --- /dev/null +++ b/src/main/java/com/study/spring1team/global/apiPayload/ApiResponse.java @@ -0,0 +1,38 @@ +package com.study.spring1team.global.apiPayload; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.study.spring1team.global.apiPayload.code.BaseErrorCode; +import com.study.spring1team.global.apiPayload.code.BaseSuccessCode; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +@JsonPropertyOrder({"isSuccess", "code", "message", "result"}) +public class ApiResponse { + + @JsonProperty("isSuccess") + private final Boolean isSuccess; + + @JsonProperty("code") + private final String code; + + @JsonProperty("message") + private final String message; + + @JsonInclude(JsonInclude.Include.NON_NULL) // 결과가 null일 때 JSON에서 아예 안 보이게 함 + @JsonProperty("result") + private T result; + + // 성공한 경우 (result 포함) + public static ApiResponse onSuccess(BaseSuccessCode code, T result) { + return new ApiResponse<>(true, code.getCode(), code.getMessage(), result); + } + + // 실패한 경우 (result 포함) + public static ApiResponse onFailure(BaseErrorCode code, T result) { + return new ApiResponse<>(false, code.getCode(), code.getMessage(), result); + } +} \ No newline at end of file diff --git a/src/main/java/com/study/spring1team/global/apiPayload/code/BaseErrorCode.java b/src/main/java/com/study/spring1team/global/apiPayload/code/BaseErrorCode.java new file mode 100644 index 0000000..886f201 --- /dev/null +++ b/src/main/java/com/study/spring1team/global/apiPayload/code/BaseErrorCode.java @@ -0,0 +1,9 @@ +package com.study.spring1team.global.apiPayload.code; + +import org.springframework.http.HttpStatus; + +public interface BaseErrorCode { + HttpStatus getStatus(); + String getCode(); + String getMessage(); +} \ No newline at end of file diff --git a/src/main/java/com/study/spring1team/global/apiPayload/code/BaseSuccessCode.java b/src/main/java/com/study/spring1team/global/apiPayload/code/BaseSuccessCode.java new file mode 100644 index 0000000..1b8f966 --- /dev/null +++ b/src/main/java/com/study/spring1team/global/apiPayload/code/BaseSuccessCode.java @@ -0,0 +1,9 @@ +package com.study.spring1team.global.apiPayload.code; + +import org.springframework.http.HttpStatus; + +public interface BaseSuccessCode { + HttpStatus getStatus(); + String getCode(); + String getMessage(); +} \ No newline at end of file diff --git a/src/main/java/com/study/spring1team/global/apiPayload/code/GeneralErrorCode.java b/src/main/java/com/study/spring1team/global/apiPayload/code/GeneralErrorCode.java new file mode 100644 index 0000000..8026618 --- /dev/null +++ b/src/main/java/com/study/spring1team/global/apiPayload/code/GeneralErrorCode.java @@ -0,0 +1,28 @@ +package com.study.spring1team.global.apiPayload.code; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum GeneralErrorCode implements BaseErrorCode{ + + BAD_REQUEST(HttpStatus.BAD_REQUEST, + "COMMON400_1", + "잘못된 요청입니다."), + UNAUTHORIZED(HttpStatus.UNAUTHORIZED, + "AUTH401_1", + "인증이 필요합니다."), + FORBIDDEN(HttpStatus.FORBIDDEN, + "AUTH403_1", + "요청이 거부되었습니다."), + NOT_FOUND(HttpStatus.NOT_FOUND, + "COMMON404_1", + "요청한 리소스를 찾을 수 없습니다."), + ; + + private final HttpStatus status; + private final String code; + private final String message; +} diff --git a/src/main/java/com/study/spring1team/global/apiPayload/code/GeneralSuccessCode.java b/src/main/java/com/study/spring1team/global/apiPayload/code/GeneralSuccessCode.java new file mode 100644 index 0000000..0584cd8 --- /dev/null +++ b/src/main/java/com/study/spring1team/global/apiPayload/code/GeneralSuccessCode.java @@ -0,0 +1,15 @@ +package com.study.spring1team.global.apiPayload.code; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum GeneralSuccessCode implements BaseSuccessCode { + OK(HttpStatus.OK, "COMMON200", "요청에 성공하였습니다."); + + private final HttpStatus status; + private final String code; + private final String message; +} \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties deleted file mode 100644 index ed2c030..0000000 --- a/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ -spring.application.name=spring-1team diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..afedd00 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,19 @@ +spring: + application: + name: "spring-1team" + + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: ${DB_URL} + username: ${DB_USER} + password: ${DB_PW} + + jpa: + database: mysql + database-platform: org.hibernate.dialect.MySQLDialect + show-sql: true + hibernate: + ddl-auto: update + properties: + hibernate: + format_sql: true \ No newline at end of file From 6c32eb0e99bbe59e5ee587a668984129cd11b147 Mon Sep 17 00:00:00 2001 From: bsh-ko Date: Tue, 17 Mar 2026 22:59:20 +0900 Subject: [PATCH 02/11] =?UTF-8?q?feat:=20=EC=BB=A4=EC=8A=A4=ED=85=80=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../apiPayload/exception/GeneralException.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/main/java/com/study/spring1team/global/apiPayload/exception/GeneralException.java diff --git a/src/main/java/com/study/spring1team/global/apiPayload/exception/GeneralException.java b/src/main/java/com/study/spring1team/global/apiPayload/exception/GeneralException.java new file mode 100644 index 0000000..9798ebc --- /dev/null +++ b/src/main/java/com/study/spring1team/global/apiPayload/exception/GeneralException.java @@ -0,0 +1,14 @@ +package com.study.spring1team.global.apiPayload.exception; + +import com.study.spring1team.global.apiPayload.code.BaseErrorCode; +import lombok.Getter; + +@Getter +public class GeneralException extends RuntimeException { + private final BaseErrorCode code; + + public GeneralException(BaseErrorCode code) { + super(code.getMessage()); + this.code = code; + } +} From 187e989b858eb6d06d9ab9c6fc0d939e8cd534ce Mon Sep 17 00:00:00 2001 From: bsh-ko Date: Tue, 17 Mar 2026 23:10:44 +0900 Subject: [PATCH 03/11] =?UTF-8?q?feat:=20=EC=A0=84=EC=97=AD=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EC=B2=98=EB=A6=AC=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/GlobalExceptionHandler.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/main/java/com/study/spring1team/global/apiPayload/exception/GlobalExceptionHandler.java diff --git a/src/main/java/com/study/spring1team/global/apiPayload/exception/GlobalExceptionHandler.java b/src/main/java/com/study/spring1team/global/apiPayload/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..483fc1d --- /dev/null +++ b/src/main/java/com/study/spring1team/global/apiPayload/exception/GlobalExceptionHandler.java @@ -0,0 +1,28 @@ +package com.study.spring1team.global.apiPayload.exception; + +import com.study.spring1team.global.apiPayload.ApiResponse; +import com.study.spring1team.global.apiPayload.code.BaseErrorCode; +import com.study.spring1team.global.apiPayload.code.GeneralErrorCode; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +@RestControllerAdvice +public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { + + @ExceptionHandler(GeneralException.class) + public ResponseEntity> handleGeneralException(GeneralException e) { + BaseErrorCode code = e.getCode(); + return ResponseEntity + .status(code.getStatus()) + .body(ApiResponse.onFailure(code, null)); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity> handleAllException(Exception e) { + return ResponseEntity + .status(GeneralErrorCode.BAD_REQUEST.getStatus()) + .body(ApiResponse.onFailure(GeneralErrorCode.BAD_REQUEST, null)); + } +} \ No newline at end of file From 263f722f0e2a61a4f6a76ad2c22d3237024f7899 Mon Sep 17 00:00:00 2001 From: bsh-ko Date: Wed, 18 Mar 2026 17:48:43 +0900 Subject: [PATCH 04/11] =?UTF-8?q?feat:=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20dto?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 + .../controller/PostController.java | 17 +++++++++++++++++ .../study/spring1team/dto/PostRequestDTO.java | 19 +++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 src/main/java/com/study/spring1team/controller/PostController.java create mode 100644 src/main/java/com/study/spring1team/dto/PostRequestDTO.java diff --git a/build.gradle b/build.gradle index d62ae85..f177747 100644 --- a/build.gradle +++ b/build.gradle @@ -27,6 +27,7 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-webmvc' + implementation 'org.springframework.boot:spring-boot-starter-validation' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok' diff --git a/src/main/java/com/study/spring1team/controller/PostController.java b/src/main/java/com/study/spring1team/controller/PostController.java new file mode 100644 index 0000000..5ac3fd5 --- /dev/null +++ b/src/main/java/com/study/spring1team/controller/PostController.java @@ -0,0 +1,17 @@ +package com.study.spring1team.controller; + +import com.study.spring1team.global.apiPayload.ApiResponse; +import com.study.spring1team.dto.PostRequestDTO; +import com.study.spring1team.global.apiPayload.code.GeneralSuccessCode; +import jakarta.validation.Valid; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/posts") +public class PostController { + + @PostMapping("/") + public ApiResponse createPost(@Valid @RequestBody PostRequestDTO request) { + return ApiResponse.onSuccess(GeneralSuccessCode.OK, "게시글이 성공적으로 생성되었습니다."); + } +} \ No newline at end of file diff --git a/src/main/java/com/study/spring1team/dto/PostRequestDTO.java b/src/main/java/com/study/spring1team/dto/PostRequestDTO.java new file mode 100644 index 0000000..8675c59 --- /dev/null +++ b/src/main/java/com/study/spring1team/dto/PostRequestDTO.java @@ -0,0 +1,19 @@ +package com.study.spring1team.dto; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Getter; + +@Getter +public class PostRequestDTO { + + @NotBlank(message = "제목은 필수 입력 항목입니다.") + @Size(min = 1, max = 50, message = "제목은 1자 이상 50자 이하로 입력해주세요.") + private String title; + + @NotBlank(message = "내용은 필수 입력 항목입니다.") + private String content; + + @NotBlank(message = "작성자는 필수 입력 항목입니다.") + private String author; +} \ No newline at end of file From 512d9d5955ea4c067c7aedbbb71b4647b0bafc51 Mon Sep 17 00:00:00 2001 From: bsh-ko Date: Wed, 18 Mar 2026 17:49:23 +0900 Subject: [PATCH 05/11] =?UTF-8?q?feat:=20swagger=20=EC=84=A4=EC=A0=95=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 --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index f177747..ef1d0ed 100644 --- a/build.gradle +++ b/build.gradle @@ -28,6 +28,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-webmvc' implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok' From 8a262a073d531e7911ea54e61b54f94ae7da9655 Mon Sep 17 00:00:00 2001 From: bsh-ko Date: Wed, 18 Mar 2026 17:56:19 +0900 Subject: [PATCH 06/11] =?UTF-8?q?bug:=20swagger=20=EC=98=A4=EB=A5=98=20-?= =?UTF-8?q?=20=EC=84=A4=EC=A0=95=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index ef1d0ed..7cdc37b 100644 --- a/build.gradle +++ b/build.gradle @@ -26,9 +26,9 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - implementation 'org.springframework.boot:spring-boot-starter-webmvc' + implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-validation' - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0' + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.5.0' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok' From 238d2d911e4a5971508a313e3cc7b47c1f8c56a1 Mon Sep 17 00:00:00 2001 From: bsh-ko Date: Wed, 18 Mar 2026 21:22:55 +0900 Subject: [PATCH 07/11] =?UTF-8?q?bug:=20swagger=20JPA=20=EA=B4=80=EB=A0=A8?= =?UTF-8?q?=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=98=A4=EB=A5=98=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 13 ++++--- .../exception/GlobalExceptionHandler.java | 7 +++- .../global/config/SwaggerConfig.java | 36 +++++++++++++++++++ src/main/resources/application.yml | 13 ++++++- 4 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/study/spring1team/global/config/SwaggerConfig.java diff --git a/build.gradle b/build.gradle index 7cdc37b..66fd456 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '4.0.3' + id 'org.springframework.boot' version '3.5.11' id 'io.spring.dependency-management' version '1.1.7' } @@ -28,13 +28,18 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-validation' - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.5.0' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok' - testImplementation 'org.springframework.boot:spring-boot-starter-data-jpa-test' - testImplementation 'org.springframework.boot:spring-boot-starter-webmvc-test' + testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + + // Swagger + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.13' + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-api:2.8.13' + // Validation + implementation 'org.springframework.boot:spring-boot-starter-validation' } tasks.named('test') { diff --git a/src/main/java/com/study/spring1team/global/apiPayload/exception/GlobalExceptionHandler.java b/src/main/java/com/study/spring1team/global/apiPayload/exception/GlobalExceptionHandler.java index 483fc1d..22b5bd6 100644 --- a/src/main/java/com/study/spring1team/global/apiPayload/exception/GlobalExceptionHandler.java +++ b/src/main/java/com/study/spring1team/global/apiPayload/exception/GlobalExceptionHandler.java @@ -3,6 +3,7 @@ import com.study.spring1team.global.apiPayload.ApiResponse; import com.study.spring1team.global.apiPayload.code.BaseErrorCode; import com.study.spring1team.global.apiPayload.code.GeneralErrorCode; +import jakarta.servlet.ServletException; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @@ -20,7 +21,11 @@ public ResponseEntity> handleGeneralException(GeneralException } @ExceptionHandler(Exception.class) - public ResponseEntity> handleAllException(Exception e) { + public ResponseEntity> handleAllException(Exception e) throws ServletException { + if (e instanceof jakarta.servlet.ServletException) { + System.out.println("발생한 에러 클래스: " + e.getClass().getName()); + throw (jakarta.servlet.ServletException) e; + } return ResponseEntity .status(GeneralErrorCode.BAD_REQUEST.getStatus()) .body(ApiResponse.onFailure(GeneralErrorCode.BAD_REQUEST, null)); diff --git a/src/main/java/com/study/spring1team/global/config/SwaggerConfig.java b/src/main/java/com/study/spring1team/global/config/SwaggerConfig.java new file mode 100644 index 0000000..0c66142 --- /dev/null +++ b/src/main/java/com/study/spring1team/global/config/SwaggerConfig.java @@ -0,0 +1,36 @@ +package com.study.spring1team.global.config; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import io.swagger.v3.oas.models.servers.Server; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SwaggerConfig { + + @Bean + public OpenAPI swagger() { + Info info = new Info().title("Project").description("Project Swagger").version("0.0.1"); + + // JWT 토큰 헤더 방식 + String securityScheme = "JWT TOKEN"; + SecurityRequirement securityRequirement = new SecurityRequirement().addList(securityScheme); + + Components components = new Components() + .addSecuritySchemes(securityScheme, new SecurityScheme() + .name(securityScheme) + .type(SecurityScheme.Type.HTTP) + .scheme("Bearer") + .bearerFormat("JWT")); + + return new OpenAPI() + .info(info) + .addServersItem(new Server().url("/")) + .addSecurityItem(securityRequirement) + .components(components); + } +} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index afedd00..c7d6dfc 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -16,4 +16,15 @@ spring: ddl-auto: update properties: hibernate: - format_sql: true \ No newline at end of file + format_sql: true + +springdoc: + default-consume-media-type: application/json + api-docs: + path: /v3/api-docs + swagger-ui: + path: /swagger-ui.html + groups-order: DESC + operations-sorter: alpha + disable-swagger-default-url: true + display-request-duration: true \ No newline at end of file From b4c04d303709a5a228f407de8ffdcccea977f9e7 Mon Sep 17 00:00:00 2001 From: bsh-ko Date: Thu, 19 Mar 2026 19:53:37 +0900 Subject: [PATCH 08/11] =?UTF-8?q?fix:=20url=20/=20=EB=B9=BC=EA=B3=A0=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/study/spring1team/controller/PostController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/study/spring1team/controller/PostController.java b/src/main/java/com/study/spring1team/controller/PostController.java index 5ac3fd5..558e838 100644 --- a/src/main/java/com/study/spring1team/controller/PostController.java +++ b/src/main/java/com/study/spring1team/controller/PostController.java @@ -10,7 +10,7 @@ @RequestMapping("/posts") public class PostController { - @PostMapping("/") + @PostMapping() public ApiResponse createPost(@Valid @RequestBody PostRequestDTO request) { return ApiResponse.onSuccess(GeneralSuccessCode.OK, "게시글이 성공적으로 생성되었습니다."); } From eeb3fe35cbecbe564446d4ea2f13e5bb9f26effe Mon Sep 17 00:00:00 2001 From: bsh-ko Date: Wed, 25 Mar 2026 22:26:39 +0900 Subject: [PATCH 09/11] =?UTF-8?q?feat:=20=EB=8F=84=EC=BB=A4=EB=A1=9C=20db?= =?UTF-8?q?=20=EC=97=B0=EA=B2=B0=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docker-compose.yml diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..e69de29 From f882de7dbab22671b5d8a426b1d4cb6de9e4b4d3 Mon Sep 17 00:00:00 2001 From: bsh-ko Date: Wed, 25 Mar 2026 23:42:24 +0900 Subject: [PATCH 10/11] =?UTF-8?q?feat:=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5/=EC=A1=B0=ED=9A=8C=20API=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20=EB=B0=8F=20Docker=20DB=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 7 ++++ docker-compose.yml | 12 +++++++ .../spring1team/Spring1teamApplication.java | 2 ++ .../ping}/controller/PingController.java | 2 +- .../post}/controller/PostController.java | 17 ++++++++-- .../{ => domain/post}/dto/PostRequestDTO.java | 2 +- .../domain/post/dto/PostResponseDTO.java | 4 +++ .../domain/post/entity/Category.java | 26 ++++++++++++++ .../spring1team/domain/post/entity/Post.java | 34 +++++++++++++++++++ .../post/repository/PostRepository.java | 7 ++++ .../domain/post/service/PostService.java | 31 +++++++++++++++++ .../spring1team/domain/user/entity/User.java | 29 ++++++++++++++++ .../spring1team/global/entity/BaseEntity.java | 25 ++++++++++++++ 13 files changed, 194 insertions(+), 4 deletions(-) rename src/main/java/com/study/spring1team/{ => domain/ping}/controller/PingController.java (90%) rename src/main/java/com/study/spring1team/{ => domain/post}/controller/PostController.java (50%) rename src/main/java/com/study/spring1team/{ => domain/post}/dto/PostRequestDTO.java (92%) create mode 100644 src/main/java/com/study/spring1team/domain/post/dto/PostResponseDTO.java create mode 100644 src/main/java/com/study/spring1team/domain/post/entity/Category.java create mode 100644 src/main/java/com/study/spring1team/domain/post/entity/Post.java create mode 100644 src/main/java/com/study/spring1team/domain/post/repository/PostRepository.java create mode 100644 src/main/java/com/study/spring1team/domain/post/service/PostService.java create mode 100644 src/main/java/com/study/spring1team/domain/user/entity/User.java create mode 100644 src/main/java/com/study/spring1team/global/entity/BaseEntity.java diff --git a/.gitignore b/.gitignore index c2065bc..e7c2888 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,10 @@ out/ ### VS Code ### .vscode/ + +# 데이터베이스 데이터 폴더 제외 +/mysql_data/ + +# OS 관련 임시 파일 +.DS_Store +Thumbs.db \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index e69de29..7c0cf6e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -0,0 +1,12 @@ +version: '3.8' +services: + db: + image: mysql:8.0 + container_name: spring-study-db + ports: + - "3307:3306" + environment: + MYSQL_ROOT_PASSWORD: tngus3872 + MYSQL_DATABASE: spring-1team + volumes: + - ./mysql_data:/var/lib/mysql \ No newline at end of file diff --git a/src/main/java/com/study/spring1team/Spring1teamApplication.java b/src/main/java/com/study/spring1team/Spring1teamApplication.java index f173fc6..c32833f 100644 --- a/src/main/java/com/study/spring1team/Spring1teamApplication.java +++ b/src/main/java/com/study/spring1team/Spring1teamApplication.java @@ -2,7 +2,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +@EnableJpaAuditing @SpringBootApplication public class Spring1teamApplication { diff --git a/src/main/java/com/study/spring1team/controller/PingController.java b/src/main/java/com/study/spring1team/domain/ping/controller/PingController.java similarity index 90% rename from src/main/java/com/study/spring1team/controller/PingController.java rename to src/main/java/com/study/spring1team/domain/ping/controller/PingController.java index a11be03..7cfcd92 100644 --- a/src/main/java/com/study/spring1team/controller/PingController.java +++ b/src/main/java/com/study/spring1team/domain/ping/controller/PingController.java @@ -1,4 +1,4 @@ -package com.study.spring1team.controller; +package com.study.spring1team.domain.ping.controller; import com.study.spring1team.global.apiPayload.ApiResponse; import com.study.spring1team.global.apiPayload.code.GeneralSuccessCode; diff --git a/src/main/java/com/study/spring1team/controller/PostController.java b/src/main/java/com/study/spring1team/domain/post/controller/PostController.java similarity index 50% rename from src/main/java/com/study/spring1team/controller/PostController.java rename to src/main/java/com/study/spring1team/domain/post/controller/PostController.java index 558e838..516efc5 100644 --- a/src/main/java/com/study/spring1team/controller/PostController.java +++ b/src/main/java/com/study/spring1team/domain/post/controller/PostController.java @@ -1,17 +1,30 @@ -package com.study.spring1team.controller; +package com.study.spring1team.domain.post.controller; +import com.study.spring1team.domain.post.entity.Post; +import com.study.spring1team.domain.post.service.PostService; import com.study.spring1team.global.apiPayload.ApiResponse; -import com.study.spring1team.dto.PostRequestDTO; +import com.study.spring1team.domain.post.dto.PostRequestDTO; import com.study.spring1team.global.apiPayload.code.GeneralSuccessCode; import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; +import java.util.List; + @RestController @RequestMapping("/posts") +@RequiredArgsConstructor public class PostController { + private final PostService postService; @PostMapping() public ApiResponse createPost(@Valid @RequestBody PostRequestDTO request) { + postService.createPost(request); return ApiResponse.onSuccess(GeneralSuccessCode.OK, "게시글이 성공적으로 생성되었습니다."); } + + @GetMapping + public List getPosts() { + return postService.getPostList(); + } } \ No newline at end of file diff --git a/src/main/java/com/study/spring1team/dto/PostRequestDTO.java b/src/main/java/com/study/spring1team/domain/post/dto/PostRequestDTO.java similarity index 92% rename from src/main/java/com/study/spring1team/dto/PostRequestDTO.java rename to src/main/java/com/study/spring1team/domain/post/dto/PostRequestDTO.java index 8675c59..7d928bb 100644 --- a/src/main/java/com/study/spring1team/dto/PostRequestDTO.java +++ b/src/main/java/com/study/spring1team/domain/post/dto/PostRequestDTO.java @@ -1,4 +1,4 @@ -package com.study.spring1team.dto; +package com.study.spring1team.domain.post.dto; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.Size; diff --git a/src/main/java/com/study/spring1team/domain/post/dto/PostResponseDTO.java b/src/main/java/com/study/spring1team/domain/post/dto/PostResponseDTO.java new file mode 100644 index 0000000..ce4ffbc --- /dev/null +++ b/src/main/java/com/study/spring1team/domain/post/dto/PostResponseDTO.java @@ -0,0 +1,4 @@ +package com.study.spring1team.domain.post.dto; + +public class PostResponseDTO { +} diff --git a/src/main/java/com/study/spring1team/domain/post/entity/Category.java b/src/main/java/com/study/spring1team/domain/post/entity/Category.java new file mode 100644 index 0000000..8257270 --- /dev/null +++ b/src/main/java/com/study/spring1team/domain/post/entity/Category.java @@ -0,0 +1,26 @@ +package com.study.spring1team.domain.post.entity; + +import com.study.spring1team.global.entity.BaseEntity; +import jakarta.persistence.*; +import lombok.*; + +import java.util.ArrayList; +import java.util.List; + +@Entity +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class Category extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, length = 20) + private String name; + + @OneToMany(mappedBy = "category", cascade = CascadeType.ALL) + private List postList = new ArrayList<>(); +} \ No newline at end of file diff --git a/src/main/java/com/study/spring1team/domain/post/entity/Post.java b/src/main/java/com/study/spring1team/domain/post/entity/Post.java new file mode 100644 index 0000000..6c197f6 --- /dev/null +++ b/src/main/java/com/study/spring1team/domain/post/entity/Post.java @@ -0,0 +1,34 @@ +package com.study.spring1team.domain.post.entity; + +import com.study.spring1team.domain.user.entity.User; +import com.study.spring1team.global.entity.BaseEntity; +import jakarta.persistence.*; +import lombok.*; + +import java.util.ArrayList; + +@Entity +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class Post extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, length = 50) + private String title; + + @Column(columnDefinition = "TEXT", nullable = false) + private String content; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User author; // 작성자 매핑 + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "category_id") + private Category category; // 카테고리 매핑 +} \ No newline at end of file diff --git a/src/main/java/com/study/spring1team/domain/post/repository/PostRepository.java b/src/main/java/com/study/spring1team/domain/post/repository/PostRepository.java new file mode 100644 index 0000000..4cc486f --- /dev/null +++ b/src/main/java/com/study/spring1team/domain/post/repository/PostRepository.java @@ -0,0 +1,7 @@ +package com.study.spring1team.domain.post.repository; + +import com.study.spring1team.domain.post.entity.Post; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface PostRepository extends JpaRepository { +} \ No newline at end of file diff --git a/src/main/java/com/study/spring1team/domain/post/service/PostService.java b/src/main/java/com/study/spring1team/domain/post/service/PostService.java new file mode 100644 index 0000000..632f537 --- /dev/null +++ b/src/main/java/com/study/spring1team/domain/post/service/PostService.java @@ -0,0 +1,31 @@ +package com.study.spring1team.domain.post.service; + +import com.study.spring1team.domain.post.dto.PostRequestDTO; +import com.study.spring1team.domain.post.entity.Post; +import com.study.spring1team.domain.post.repository.PostRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@Transactional +@RequiredArgsConstructor +public class PostService { + + private final PostRepository postRepository; + + public Long createPost(PostRequestDTO request) { + Post post = Post.builder() + .title(request.getTitle()) + .content(request.getContent()) + .build(); + + return postRepository.save(post).getId(); + } + + public List getPostList() { + return postRepository.findAll(); + } +} \ No newline at end of file diff --git a/src/main/java/com/study/spring1team/domain/user/entity/User.java b/src/main/java/com/study/spring1team/domain/user/entity/User.java new file mode 100644 index 0000000..32b0691 --- /dev/null +++ b/src/main/java/com/study/spring1team/domain/user/entity/User.java @@ -0,0 +1,29 @@ +package com.study.spring1team.domain.user.entity; + +import com.study.spring1team.domain.post.entity.Post; +import com.study.spring1team.global.entity.BaseEntity; +import jakarta.persistence.*; +import lombok.*; + +import java.util.ArrayList; +import java.util.List; + +@Entity +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class User extends BaseEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false, length = 20) + private String name; + + @Column(nullable = false, unique = true, length = 50) + private String email; + + @OneToMany(mappedBy = "author", cascade = CascadeType.ALL) + private List postList = new ArrayList<>(); +} diff --git a/src/main/java/com/study/spring1team/global/entity/BaseEntity.java b/src/main/java/com/study/spring1team/global/entity/BaseEntity.java new file mode 100644 index 0000000..5ec7a0b --- /dev/null +++ b/src/main/java/com/study/spring1team/global/entity/BaseEntity.java @@ -0,0 +1,25 @@ +package com.study.spring1team.global.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.MappedSuperclass; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import lombok.Getter; +import java.time.LocalDateTime; + +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) +@Getter +public abstract class BaseEntity { + + @CreatedDate + @Column(name= "created_at", nullable = false) + private LocalDateTime createdAt; + + @LastModifiedDate + @Column(name= "updated_at", nullable = false) + private LocalDateTime updatedAt; +} From 5a8848ef3aba73aa4e8369c515dc21ab99f060f4 Mon Sep 17 00:00:00 2001 From: bsh-ko Date: Thu, 26 Mar 2026 11:40:58 +0900 Subject: [PATCH 11/11] =?UTF-8?q?feat:=20=EB=B9=84=EB=B0=80=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=ED=95=84=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/study/spring1team/domain/user/entity/User.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/study/spring1team/domain/user/entity/User.java b/src/main/java/com/study/spring1team/domain/user/entity/User.java index 32b0691..8daa233 100644 --- a/src/main/java/com/study/spring1team/domain/user/entity/User.java +++ b/src/main/java/com/study/spring1team/domain/user/entity/User.java @@ -18,6 +18,9 @@ public class User extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + @Column(nullable = false, length = 100) + private String password; + @Column(nullable = false, length = 20) private String name;