From 15060563d4aaede1501a79c575bbd94a616c0548 Mon Sep 17 00:00:00 2001 From: jickDo Date: Sat, 13 Sep 2025 21:17:10 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=EC=9E=84=EC=8B=9C=20=EC=BD=94?= =?UTF-8?q?=EC=8A=A4=20=EC=83=81=EC=84=B8=20=EB=B6=88=EB=9F=AC=EC=98=A4?= =?UTF-8?q?=EA=B8=B0=20ssr=EB=B2=84=EC=A0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 + .../core/course/api/CourseThymeleaf.java | 178 +++++++++++++++ .../resources/templates/course/course.html | 216 ++++++++++++++++++ 3 files changed, 398 insertions(+) create mode 100644 src/main/java/com/unretired/core/course/api/CourseThymeleaf.java create mode 100644 src/main/resources/templates/course/course.html diff --git a/build.gradle b/build.gradle index bd850107..be1875c1 100644 --- a/build.gradle +++ b/build.gradle @@ -123,6 +123,10 @@ dependencies { //Redis implementation 'org.springframework.boot:spring-boot-starter-data-redis' + + //Thymeleaf + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' + } def buildDir = layout.buildDirectory.get().asFile diff --git a/src/main/java/com/unretired/core/course/api/CourseThymeleaf.java b/src/main/java/com/unretired/core/course/api/CourseThymeleaf.java new file mode 100644 index 00000000..3c23e9b7 --- /dev/null +++ b/src/main/java/com/unretired/core/course/api/CourseThymeleaf.java @@ -0,0 +1,178 @@ +package com.unretired.core.course.api; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +@Controller +@RequiredArgsConstructor +@RequestMapping("/api/course/ssr") +public class CourseThymeleaf { + @GetMapping("") + public String showCourse(Model model) { + + // 페이지 기본 정보 + Map pageInfo = Map.of( + "mainTitle", "28년 차 PD가 들려주는 PD 지망생이 절대 하지 말아야 할 것 세 가지", + "mainDescription", "PD라는 일은 결코 쉽지 않습니다. 그렇지만 28년 동안 PD로 살아온 것은, 이 직업만이 주는 분명한 보람과 성취감 때문입니다.", + "subDescription", "여전히 현직에서 일하고 있는 PD로서, 방송 PD를 준비하시는 분들께 방송 PD 준비 과정과 기획/연출을 위한 실질적인 팁을 아낌없이 전달하고 싶습니다.", + "recommendTitle", "강의 추천 대상", + "learningTitle", "함께할 학습 흐름", + "questions", Arrays.asList( + "PD가 꿈인데, 어떤 부분이 힘든지 알고 싶습니다.", + "PD가 되려면 필요한 덕목이 있을까요?", + "소심한데, 현장지휘에 어려움을 겪진 않을까요?", + "기획은 어디서부터 어떻게 해야 잘 할 수 있을까요?" + ), + "buttonText", "갤러리 전체보기" + ); + + // 학습 흐름 4개 이미지 (위쪽) + List> items = Arrays.asList( + Map.of( + "title", "아이디어가 어떻게 프로그램이 될까요?", + "description", "기획에서 연출까지,\nPD의 실제 과정을 들어봅시다.", + "imageUrl", "https://cdn.unretired.co.kr/img/sg-sub1.png", + "date", "2024.03.15" + ), + Map.of( + "title", "예상치 못한 돌발 상황이 생긴다면?", + "description", "협업 속 갈등을 줄이고 현장을 지켜낸\n" + + "PD의 비법을 알려드립니다.", + "imageUrl", "https://cdn.unretired.co.kr/img/sg-sub2.png", + "date", "2024.03.10" + ), + Map.of( + "title", "결과보다 중요한건 과정!", + "description", "새로운 시도를 두려워하지 않았던 이유,\n" + + "대중의 마음을 움직이는 과정의 힘을 알아봅니다.", + "imageUrl", "https://cdn.unretired.co.kr/img/sg-sub3.png", + "date", "2024.03.08" + ), + Map.of( + "title", "PD가 꼭 알아야 할 현장 꿀팁", + "description", "현장에서 직접 겪은 에피소드와 현실적인 조언,\n" + + "PD에게 꼭 필요한 실전 노하우를 전해드립니다.", + "imageUrl", "https://cdn.unretired.co.kr/img/sg-sub4.png", + "date", "2024.03.05" + ) + ); + + // 메인 갤러리 아이템들 (아래쪽 - 세로 나열) + List> galleryItems = Arrays.asList( + Map.of( + "title", "", + "description", "저는 1997년 기업형 프로덕션에서 PD로 첫발을 내디뎠습니다.첫 해외 로케이션 현장에서 동료들과 땀 흘리며 수많은 돌발 상황에 대처해 나간 기억이 떠오릅니다.현장 스탭들과 호흡하며 PD일의 즐거움을 알게 되었고 이후 28년 동안 연출자의 길을 걸어오고 있습니다.", + "imageUrl", "https://cdn.unretired.co.kr/img/sg-main1.jpg", + "caption", "여전히 재밌는 길을 걷고 있습니다" + ), + Map.of( + "title", "", + "description", "방송 현장에서 겪게 되는 수많은 돌발 상황들과 예기치 못한 변수들을 어떻게 대처해야 하는지에 대한 실질적인 경험담을 들려드립니다.현장의 생생한 이야기와 함께 PD로서 성장할 수 있었던 소중한 경험들을 나누고자 합니다.매순간이 배움의 연속이었고 그 모든 과정이 지금의 저를 만들었습니다.", + "imageUrl", "https://cdn.unretired.co.kr/img/sg-main2.jpg", + "caption", "" + ), + Map.of( + "title", "", + "description", "현장에서 사용되는 다양한 장비들의 특성을 이해하고 효율적으로 활용하는 방법에 대해 설명합니다.기술적인 부분뿐만 아니라 현장 상황에 맞는 최적의 장비 선택과 운용 노하우를 전수합니다.안전하고 체계적인 장비 관리가 성공적인 방송 제작의 핵심이라는 것을 많은 경험을 통해 깨달았습니다.", + "imageUrl", "https://cdn.unretired.co.kr/img/sg-main3.jpg", + "caption", "기술과 감성의 조화로운 만남" + ), + Map.of( + "title", "", + "description", "성공적인 프로그램 제작을 위해서는 다양한 분야의 전문가들과의 원활한 소통과 협력이 필수입니다.각 분야별 전문가들과 어떻게 효과적으로 협업할 수 있는지에 대한 구체적인 방법론과 실제 경험을 바탕으로 한 협업의 핵심 요소들을 제시합니다.혼자서는 절대 만들어낼 수 없는 결과물을 함께 완성해나가는 기쁨을 알려드리고 싶습니다.", + "imageUrl", "https://cdn.unretired.co.kr/img/sg-main4.jpg", + "caption", "" + ), + Map.of( + "title", "", + "description", "현장에서의 리더십과 의사소통 능력은 PD에게 가장 중요한 자질 중 하나입니다.다양한 성격과 전문성을 가진 사람들을 하나로 모으고 공통의 목표를 향해 나아가게 하는 리더십의 노하우를 실제 경험담과 함께 들려드립니다.때로는 강하게, 때로는 부드럽게 상황에 맞는 리더십을 발휘하는 방법을 알려드리겠습니다.", + "imageUrl", "https://cdn.unretired.co.kr/img/sg-main5.jpg", + "caption", "함께하는 힘이 만들어내는 기적" + ), + Map.of( + "title", "", + "description", "위기 상황에서의 팀 결속력과 문제 해결 능력은 진정한 팀워크를 보여주는 지표입니다.예상치 못한 상황에서도 흔들리지 않는 팀을 만들어가는 과정과 그 속에서 얻은 값진 교훈들을 나누고자 합니다.진정한 프로페셔널이 되기 위해서는 기술적 완성도와 함께 인간적 성숙함이 필요하다는 것을 깨달았습니다.", + "imageUrl", "https://cdn.unretired.co.kr/img/sg-main6.jpg", + "caption", "" + ), + Map.of( + "title", "", + "description", "28년간의 PD 생활을 돌이켜보면 매 순간이 도전이었고 성장이었습니다.실패와 성공을 반복하며 쌓아온 경험들을 후배 PD들과 나누는 것이 제 마지막 사명이라고 생각합니다.여러분도 저처럼 이 길에서 큰 보람과 성취감을 느끼시길 바랍니다.PD라는 직업이 단순한 일이 아닌 자신의 인생을 완성해나가는 여정임을 알게 되실 것입니다.", + "imageUrl", "https://cdn.unretired.co.kr/img/sg-main7.jpg", + "caption", "새로운 시작을 꿈꾸는 모든 이들에게" + ), + Map.of( + "title", "", + "description", "28년간의 PD 생활을 돌이켜보면 매 순간이 도전이었고 성장이었습니다.실패와 성공을 반복하며 쌓아온 경험들을 후배 PD들과 나누는 것이 제 마지막 사명이라고 생각합니다.여러분도 저처럼 이 길에서 큰 보람과 성취감을 느끼시길 바랍니다.PD라는 직업이 단순한 일이 아닌 자신의 인생을 완성해나가는 여정임을 알게 되실 것입니다.", + "imageUrl", "https://cdn.unretired.co.kr/img/sg-main8.jpg", + "caption", "새로운 시작을 꿈꾸는 모든 이들에게" + ), + Map.of( + "title", "", + "description", "28년간의 PD 생활을 돌이켜보면 매 순간이 도전이었고 성장이었습니다.실패와 성공을 반복하며 쌓아온 경험들을 후배 PD들과 나누는 것이 제 마지막 사명이라고 생각합니다.여러분도 저처럼 이 길에서 큰 보람과 성취감을 느끼시길 바랍니다.PD라는 직업이 단순한 일이 아닌 자신의 인생을 완성해나가는 여정임을 알게 되실 것입니다.", + "imageUrl", "https://cdn.unretired.co.kr/img/sg-main10.jpg", + "caption", "새로운 시작을 꿈꾸는 모든 이들에게" + ), + Map.of( + "title", "", + "description", "28년간의 PD 생활을 돌이켜보면 매 순간이 도전이었고 성장이었습니다.실패와 성공을 반복하며 쌓아온 경험들을 후배 PD들과 나누는 것이 제 마지막 사명이라고 생각합니다.여러분도 저처럼 이 길에서 큰 보람과 성취감을 느끼시길 바랍니다.PD라는 직업이 단순한 일이 아닌 자신의 인생을 완성해나가는 여정임을 알게 되실 것입니다.", + "imageUrl", "https://cdn.unretired.co.kr/img/sg-main11.jpg", + "caption", "새로운 시작을 꿈꾸는 모든 이들에게" + ) + ); + + // 갤러리 섹션별 텍스트 (5개 섹션) + List> gallerySections = Arrays.asList( + Map.of( + "description", "저는 1997년 기업형 프로덕션에서 PD로 첫발을 내디뎠습니다.\n" + + "첫 해외 로케이션 현장에서 동료들과 땀 흘리며 수많은 돌발 상황에 대처해 나간 기억이 떠오릅니다.\n" + + "현장 스탭들과 호흡하며 PD일의 즐거움을 알게 되었고 이후 28년 동안 연출자의 길을 걸어오고 있습니다.", + "caption", "여전히 재밌는 길을 걷고 있습니다" + ), + Map.of( + "description", "방송국과 연출실에서 수십 대의 카메라와 수많은 스태프, 출연진을 지휘하며 다양한 프로그램을 만들어왔습니다.\n" + + "TV조선에서 제작본부 부장으로 근무하며 \n" + + "[찾아라! 맛있는 TV], [슈퍼디바], [애정통일 남남북녀], [모란봉 클럽], [살림 9단의 만물상], [식객 허영만의 백반기행]까지 \n" + + "시대를 대표하는 프로그램들을 기획하고 연출했습니다.\n" + + "기획에서 연출, 협업과 갈등 조율에 이르기까지, 현장이 곧 저의 학교이자 훈련장이었습니다.", + "caption", "" + ), + Map.of( + "description", "방송을 하며 가장 크게 배운 점은 ‘결과보다 과정의 힘’이었습니다. \n" + + "어떤 기획은 거절당하기도 했지만, 끝내 밀어붙여 스테디셀러로 만든 경험도 있습니다. \n" + + "저에게 방송은 늘 새로운 시도를 발견하고 대중과 공감대를 만들어내는 도전의 과정이었습니다.", + "caption", "" + ), + Map.of( + "description", "그리고 그 모든 경험의 중심에는 언제나 ‘즐거움’이라는 감정이 있었습니다. \n" + + "콘텐츠를 기획하고 현장을 지휘하며, 때로는 갈등을 조율하고 치열한 방송 환경에서 경쟁하면서도 즐거운 마음은 잃은 적이 없습니다. \n" + + "이번 강의에서는 제가 걸어온 길을 바탕으로 방송사 PD의 현실과 생생한 조언 \n" + + "그리고 ‘잘하는 PD’가 되기 위해 반드시 필요한 노하우를 전하려 합니다. \n" + + "방송을 꿈꾸는 분들에게는 현실적인 길잡이가, 이미 방송 현장에 있는 분들에게는 다시 단단해질 수 있는 시간이 되기를 바랍니다.", + "caption", "즐기는 PD가 결국 잘하는 PD가 됩니다" + ), + Map.of( + "description", "PD라는 일은 결코 쉽지 않습니다. \n" + + "하지만 이 직업만이 주는 분명한 보람과 성취감은 그 어떤 일보다 매력적이라고 자부합니다.\n" + + "PD의 길을 꿈꾸는 분들이 그 즐거움을 꼭 누리셨으면 하는 마음으로 실질적인 팁을 아낌없이 털어놓았습니다.\n" + + "현직 PD만의 노하우를 강연에서 꼭 확인하시기 바랍니다.\n" + + "그리고 현장에서 다시 만납시다.", + "caption", "PD의 길, 함께 걸어보시겠습니까?" + ) + ); + + model.addAttribute("pageInfo", pageInfo); + model.addAttribute("items", items); + model.addAttribute("galleryItems", galleryItems); + model.addAttribute("gallerySections", gallerySections); // 새로 추가 + return "course/course"; + } +} + diff --git a/src/main/resources/templates/course/course.html b/src/main/resources/templates/course/course.html new file mode 100644 index 00000000..4abadf22 --- /dev/null +++ b/src/main/resources/templates/course/course.html @@ -0,0 +1,216 @@ + + + + + + 갤러리 - 현장 작업 및 장비 소개 + + + + +
+

28년 차 PD가 들려주는 PD 지망생이 절대 하지 말아야 할 것 세 가지

+ + +
+
+ + +
+

+ PD라는 일은 결코 쉽지 않습니다. 그렇지만 28년 동안 PD로 살아온 것은, 이 직업만이 주는 분명한 보람과 성취감 때문입니다. +

+

+ 여전히 현직에서 일하고 있는 PD로서, 방송 PD를 준비하시는 분들께 방송 PD 준비 과정과 기획/연출을 위한 실질적인 팁을 아낌없이 전달하고 싶습니다. +

+ + +
+
+ + +
+ +
+

강의 추천 대상

+
+ +
+

+ PD가 꿈인데, 어떤 부분이 힘든지 알고 싶습니다. +

+
+ + +
+

+ 함께할 학습 흐름 +

+
+ + +
+
+ + +

제목

+ +

설명...

+
+
+ + + +
+

+ 방송국 PD가 직접 털어놓는, 지금 당장 써먹을 수 있는 연출 노하우 A to Z +

+
+ + +
+

+ “28년 현장을 지휘한 베테랑 PD의 방송 연출 이야기” +

+
+ + + + + \ No newline at end of file From 4e87c635892d1c964fcd5a615f88331e3e7a4e8b Mon Sep 17 00:00:00 2001 From: jickDo Date: Sat, 13 Sep 2025 21:43:19 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20=EC=A4=84=EA=B0=84=EA=B2=A9=20?= =?UTF-8?q?=EB=B0=8F=20=EC=A4=84=20=EC=A0=95=EB=A0=AC=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/templates/course/course.html | 248 ++++++++++-------- 1 file changed, 134 insertions(+), 114 deletions(-) diff --git a/src/main/resources/templates/course/course.html b/src/main/resources/templates/course/course.html index 4abadf22..82fac14d 100644 --- a/src/main/resources/templates/course/course.html +++ b/src/main/resources/templates/course/course.html @@ -17,17 +17,13 @@
-
-

+

- PD라는 일은 결코 쉽지 않습니다. 그렇지만 28년 동안 PD로 살아온 것은, 이 직업만이 주는 분명한 보람과 성취감 때문입니다.

-

- 여전히 현직에서 일하고 있는 PD로서, 방송 PD를 준비하시는 분들께 방송 PD 준비 과정과 기획/연출을 위한 실질적인 팁을 아낌없이 전달하고 싶습니다.

- -
@@ -87,128 +83,152 @@

-
-
- +
+
+ +
+
+ +
+
+ +
+
+ + +
+

캡션

+
+ + +
+

텍스트 설명

+
-
- -
-
- - -
-

캡션

-
- - -
-

텍스트 설명

-
-
- +
+
+ +
+
+ +
+
+ +
+
+ + +
+

캡션

+
+ + +
+

텍스트 설명

+
-
- -
-
- - -
-

캡션

- -
-

텍스트 설명

-
- - -
-
- -
-
- + +
+
+ +
+
+ +
+
+ +
+
+ + +
+

캡션

+
+ + +
+

텍스트 설명

+
- -
-

캡션

-
- - -
-

텍스트 설명

-
- -
-
- -
-
- +
+
+ +
+
+ +
+
+ +
+
+ + +
+

캡션

+
+ + +
+

텍스트 설명

+
- - -
-

캡션

-
- - -
-

텍스트 설명

-
- -
-
- +
+
+ +
+
+ +
+
+ +
+
+ + +
+

캡션

+
+ + +
+

텍스트 설명

+
-
- -
-
- - -
-

캡션

-
- - -
-

텍스트 설명

From 3a673975e6ef7cde5fab5dbcdb3628ee89b5b6e2 Mon Sep 17 00:00:00 2001 From: jickDo Date: Thu, 18 Sep 2025 21:19:39 +0900 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20=EC=9A=B4=EC=98=81=EC=84=9C=EB=B2=84?= =?UTF-8?q?=EC=97=90=EC=84=9C=20api=20spec=20=ED=99=95=EC=9D=B8=EC=9D=84?= =?UTF-8?q?=20=EC=9C=84=ED=95=9C=20=EC=8A=A4=ED=8E=99=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../unretired/core/course/api/CourseThymeleaf.java | 4 +++- .../core/course/api/spec/CourseThymeleafSpec.java | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/unretired/core/course/api/spec/CourseThymeleafSpec.java diff --git a/src/main/java/com/unretired/core/course/api/CourseThymeleaf.java b/src/main/java/com/unretired/core/course/api/CourseThymeleaf.java index 3c23e9b7..cc83e45b 100644 --- a/src/main/java/com/unretired/core/course/api/CourseThymeleaf.java +++ b/src/main/java/com/unretired/core/course/api/CourseThymeleaf.java @@ -1,5 +1,7 @@ package com.unretired.core.course.api; +import com.unretired.core.course.api.spec.CourseLikeApiSpec; +import com.unretired.core.course.api.spec.CourseThymeleafSpec; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; @@ -13,7 +15,7 @@ @Controller @RequiredArgsConstructor @RequestMapping("/api/course/ssr") -public class CourseThymeleaf { +public class CourseThymeleaf implements CourseThymeleafSpec { @GetMapping("") public String showCourse(Model model) { diff --git a/src/main/java/com/unretired/core/course/api/spec/CourseThymeleafSpec.java b/src/main/java/com/unretired/core/course/api/spec/CourseThymeleafSpec.java new file mode 100644 index 00000000..bb291e71 --- /dev/null +++ b/src/main/java/com/unretired/core/course/api/spec/CourseThymeleafSpec.java @@ -0,0 +1,13 @@ +package com.unretired.core.course.api.spec; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.ui.Model; + +@Tag(name = "상세 강의 ssr", description = "상세 강의 ssr") +public interface CourseThymeleafSpec { + @Operation(description = "상세 강의 ssr") + @ApiResponse(responseCode = "200") + String showCourse(Model model); +} From 3d025dc8a4b4ff6d0eb21bb153e2e7265a2f0770 Mon Sep 17 00:00:00 2001 From: jickDo Date: Thu, 18 Sep 2025 21:54:33 +0900 Subject: [PATCH 4/4] =?UTF-8?q?fix:=20prod=EB=A1=9C=20=ED=96=A5=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EC=97=90=EB=9F=AC=EB=A1=9C=EA=B7=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/unretired/core/course/api/CourseThymeleaf.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/unretired/core/course/api/CourseThymeleaf.java b/src/main/java/com/unretired/core/course/api/CourseThymeleaf.java index cc83e45b..904d74b7 100644 --- a/src/main/java/com/unretired/core/course/api/CourseThymeleaf.java +++ b/src/main/java/com/unretired/core/course/api/CourseThymeleaf.java @@ -1,7 +1,7 @@ package com.unretired.core.course.api; -import com.unretired.core.course.api.spec.CourseLikeApiSpec; import com.unretired.core.course.api.spec.CourseThymeleafSpec; +import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; @@ -16,6 +16,13 @@ @RequiredArgsConstructor @RequestMapping("/api/course/ssr") public class CourseThymeleaf implements CourseThymeleafSpec { + + @PostConstruct + public void init() { + System.out.println("========== CourseThymeleaf @PostConstruct 실행됨 =========="); + System.out.println("Bean이 Spring 컨테이너에 등록되었습니다!"); + } + @GetMapping("") public String showCourse(Model model) {