From 2a60d42e15187f0fa27ca9b8771e30b323ca0399 Mon Sep 17 00:00:00 2001 From: JangIkhwan Date: Thu, 15 Jan 2026 11:08:03 +0900 Subject: [PATCH 01/25] =?UTF-8?q?feat=20:=207=EB=8B=A8=EA=B3=84=20-=20Arti?= =?UTF-8?q?cle=EC=97=90=20imageUrl=20=ED=95=84=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/Article.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/model/Article.java b/src/main/java/model/Article.java index 7d02b6d9e..abdf5b7ad 100644 --- a/src/main/java/model/Article.java +++ b/src/main/java/model/Article.java @@ -6,18 +6,21 @@ public class Article { private String writerName; private String title; private String content; + private String imageUrl; - public Article(Long id, Long creatorId, String title, String content) { + public Article(Long id, Long creatorId, String title, String content, String imageUrl) { this.id = id; this.creatorId = creatorId; this.title = title; this.content = content; + this.imageUrl = imageUrl; } - public Article(Long creatorId, String title, String content) { + public Article(Long creatorId, String title, String content, String imageUrl) { this.creatorId = creatorId; this.title = title; this.content = content; + this.imageUrl = imageUrl; } public Long getId() { @@ -40,6 +43,10 @@ public String getContent() { return content; } + public String getImageUrl() { + return imageUrl; + } + public void setId(Long id) { this.id = id; } From 4dbd87890c7be0f4628aa39e050f5648131cf620 Mon Sep 17 00:00:00 2001 From: JangIkhwan Date: Thu, 15 Jan 2026 11:10:00 +0900 Subject: [PATCH 02/25] =?UTF-8?q?feat=20:=207=EB=8B=A8=EA=B3=84=20-=20Arti?= =?UTF-8?q?cleRepositoryImpl=EC=97=90=EC=84=9C=20=EC=BF=BC=EB=A6=AC=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/db/ArticleRepositoryImpl.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/db/ArticleRepositoryImpl.java b/src/main/java/db/ArticleRepositoryImpl.java index 9c4247632..7d441d95c 100644 --- a/src/main/java/db/ArticleRepositoryImpl.java +++ b/src/main/java/db/ArticleRepositoryImpl.java @@ -15,7 +15,7 @@ public class ArticleRepositoryImpl implements ArticleRepository { private static final Logger logger = LoggerFactory.getLogger(ArticleRepositoryImpl.class); public Article save(Article article) { - String sql = "insert into article_tbl(creatorId, title, content) values(?, ?, ?)"; + String sql = "insert into article_tbl(creatorId, title, content, imageUrl) values(?, ?, ?, ?)"; try ( Connection con = DriverManager.getConnection(JDBC_URL, USER, PASSWORD); PreparedStatement pstmt = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); @@ -23,6 +23,7 @@ public Article save(Article article) { pstmt.setLong(1, article.getCreatorId()); pstmt.setString(2, article.getTitle()); pstmt.setString(3, article.getContent()); + pstmt.setString(3, article.getImageUrl()); pstmt.executeUpdate(); @@ -41,7 +42,7 @@ public Article save(Article article) { @Override public List
findTopNLessThanByIdDecreasingOrder(int limit, long id) { - String sql = "select id, creatorId, title, content from article_tbl where id < ? order by id desc limit ?"; + String sql = "select id, creatorId, title, content, image_url from article_tbl where id < ? order by id desc limit ?"; try ( Connection con = DriverManager.getConnection(JDBC_URL, USER, PASSWORD); @@ -58,7 +59,8 @@ public List
findTopNLessThanByIdDecreasingOrder(int limit, long id) { long creatorId = rs.getLong("creatorId"); String title = rs.getString("title"); String content = rs.getString("content"); - articles.add(new Article(articleId, creatorId, title, content)); + String imageUrl = rs.getString("image_url"); + articles.add(new Article(articleId, creatorId, title, content, imageUrl)); } } return articles; From b005dfa20b5b1a7adb355b2032c1cb512898f35d Mon Sep 17 00:00:00 2001 From: JangIkhwan Date: Thu, 15 Jan 2026 11:11:15 +0900 Subject: [PATCH 03/25] =?UTF-8?q?feat=20:=207=EB=8B=A8=EA=B3=84=20-=20Crea?= =?UTF-8?q?teArticleHandler=EC=97=90=EC=84=9C=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=EB=A5=BC=20=EC=A0=80=EC=9E=A5=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 이미지가 없으면 예외 발생 - 이미지를 로컬에 저장 --- .../handler/CreateArticleHandler.java | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/src/main/java/webserver/handler/CreateArticleHandler.java b/src/main/java/webserver/handler/CreateArticleHandler.java index a51cf9f96..10802690b 100644 --- a/src/main/java/webserver/handler/CreateArticleHandler.java +++ b/src/main/java/webserver/handler/CreateArticleHandler.java @@ -3,13 +3,24 @@ import db.ArticleRepository; import model.Article; import model.User; +import webserver.exception.BadRequestException; import webserver.http.Request; import webserver.http.Response; import webserver.mvc.Handler; import webserver.mvc.ModelAndView; +import webserver.mvc.MultipartFile; import webserver.mvc.RedirectView; import webserver.util.AuthUtil; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.UUID; + public class CreateArticleHandler implements Handler { private final ArticleRepository articleRepository; @@ -26,8 +37,43 @@ public ModelAndView handle(Request request, Response response) { String title = request.getParameter("title"); String content = request.getParameter("content"); - articleRepository.save(new Article(user.getId(), title, content)); + if(request.getMultipartFiles().size() != 1){ + // todo 게시글 작성폼에서 에러문구 출력하도록 수정 + throw new BadRequestException(); + } + + MultipartFile multipartFile = request.getMultipartFiles().get(0); + + String imageUrl = null; + try { + imageUrl = saveFile(multipartFile); + } catch (IOException e) { + throw new RuntimeException(e); + } + + articleRepository.save(new Article(user.getId(), title, content, imageUrl)); return new RedirectView("/"); } + + private String saveFile(MultipartFile multipartFile) throws IOException { + InputStream in = multipartFile.getInputStream(); + String filename = multipartFile.getFilename() + UUID.randomUUID().toString(); + String projectRoot = System.getProperty("user.dir"); + Path uploadDir = Paths.get(projectRoot, "uploads", "images"); + + Files.createDirectories(uploadDir); + + Path target = uploadDir.resolve(filename); + + try (OutputStream out = Files.newOutputStream( + target, + StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING)) { + + in.transferTo(out); + } + + return filename; + } } From ab6df936fc84f0ec0cce7f6cceb24781b49bf4ee Mon Sep 17 00:00:00 2001 From: JangIkhwan Date: Thu, 15 Jan 2026 11:14:37 +0900 Subject: [PATCH 04/25] =?UTF-8?q?feat=20:=207=EB=8B=A8=EA=B3=84=20-=20Requ?= =?UTF-8?q?estHandler=EC=97=90=EC=84=9C=20BadRequestException=20=EB=B0=9C?= =?UTF-8?q?=EC=83=9D=20=EC=8B=9C=EC=97=90=20=EC=97=90=EB=9F=AC=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=EB=A5=BC=20=EB=B3=B4=EC=97=AC=EC=A3=BC?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=97=90=EB=9F=AC=20=EC=B2=98=EB=A6=AC=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/webserver/mvc/RequestHandler.java | 7 ++++--- src/main/resources/static/error/400_error.html | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 src/main/resources/static/error/400_error.html diff --git a/src/main/java/webserver/mvc/RequestHandler.java b/src/main/java/webserver/mvc/RequestHandler.java index f78917444..e345ef720 100644 --- a/src/main/java/webserver/mvc/RequestHandler.java +++ b/src/main/java/webserver/mvc/RequestHandler.java @@ -11,8 +11,8 @@ import db.UserRepositoryImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import webserver.exception.BadRequestException; import webserver.exception.MethodNotAllowedException; -import webserver.exception.RequestParsingException; import webserver.exception.StaticResourceNotFoundException; import webserver.handler.*; import webserver.http.Request; @@ -88,9 +88,10 @@ private void processRequest(OutputStream out, InputStream in) throws IOException logger.debug("method not allowed error", e); sendErrorPage(responseWriter, Response.methodNotAllowed(), new StaticResourceView("/error/405_error.html")); } - catch (RequestParsingException e){ + catch (BadRequestException e){ logger.debug("request parsing error", e); - responseWriter.write(Response.badRequest()); + sendErrorPage(responseWriter, Response.badRequest(), new StaticResourceView("/error/400_error.html")); + } catch (RuntimeException e){ logger.debug("internal server error", e); diff --git a/src/main/resources/static/error/400_error.html b/src/main/resources/static/error/400_error.html new file mode 100644 index 000000000..9d5c0ff49 --- /dev/null +++ b/src/main/resources/static/error/400_error.html @@ -0,0 +1,16 @@ + + + + + + + + + +
+
+

잘못된 요청입니다 (400 Bad Request)

+
+
+ + From 79fd1fa203103b8e35f45942f22a89a193642c7d Mon Sep 17 00:00:00 2001 From: JangIkhwan Date: Thu, 15 Jan 2026 11:34:21 +0900 Subject: [PATCH 05/25] =?UTF-8?q?fix=20:=207=EB=8B=A8=EA=B3=84=20-=20Artic?= =?UTF-8?q?leRepositoryImpl=EC=97=90=EC=84=9C=20=EC=9E=98=EB=AA=BB?= =?UTF-8?q?=EB=90=9C=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/db/ArticleRepositoryImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/db/ArticleRepositoryImpl.java b/src/main/java/db/ArticleRepositoryImpl.java index 7d441d95c..050f93d3e 100644 --- a/src/main/java/db/ArticleRepositoryImpl.java +++ b/src/main/java/db/ArticleRepositoryImpl.java @@ -15,7 +15,7 @@ public class ArticleRepositoryImpl implements ArticleRepository { private static final Logger logger = LoggerFactory.getLogger(ArticleRepositoryImpl.class); public Article save(Article article) { - String sql = "insert into article_tbl(creatorId, title, content, imageUrl) values(?, ?, ?, ?)"; + String sql = "insert into article_tbl(creatorId, title, content, image_url) values(?, ?, ?, ?)"; try ( Connection con = DriverManager.getConnection(JDBC_URL, USER, PASSWORD); PreparedStatement pstmt = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); @@ -23,7 +23,7 @@ public Article save(Article article) { pstmt.setLong(1, article.getCreatorId()); pstmt.setString(2, article.getTitle()); pstmt.setString(3, article.getContent()); - pstmt.setString(3, article.getImageUrl()); + pstmt.setString(4, article.getImageUrl()); pstmt.executeUpdate(); From 4726225a86311384c451205429b4e0a245e1d844 Mon Sep 17 00:00:00 2001 From: JangIkhwan Date: Thu, 15 Jan 2026 11:35:35 +0900 Subject: [PATCH 06/25] =?UTF-8?q?fix=20:=207=EB=8B=A8=EA=B3=84=20-=20saveF?= =?UTF-8?q?ile=EC=97=90=EC=84=9C=20=EB=B0=98=ED=99=98=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=EC=9D=98=20url=EC=9D=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/webserver/handler/CreateArticleHandler.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/webserver/handler/CreateArticleHandler.java b/src/main/java/webserver/handler/CreateArticleHandler.java index 10802690b..62e03f34d 100644 --- a/src/main/java/webserver/handler/CreateArticleHandler.java +++ b/src/main/java/webserver/handler/CreateArticleHandler.java @@ -3,7 +3,6 @@ import db.ArticleRepository; import model.Article; import model.User; -import webserver.exception.BadRequestException; import webserver.http.Request; import webserver.http.Response; import webserver.mvc.Handler; @@ -58,7 +57,7 @@ public ModelAndView handle(Request request, Response response) { private String saveFile(MultipartFile multipartFile) throws IOException { InputStream in = multipartFile.getInputStream(); - String filename = multipartFile.getFilename() + UUID.randomUUID().toString(); + String filename = UUID.randomUUID().toString() + multipartFile.getFilename(); String projectRoot = System.getProperty("user.dir"); Path uploadDir = Paths.get(projectRoot, "uploads", "images"); @@ -74,6 +73,6 @@ private String saveFile(MultipartFile multipartFile) throws IOException { in.transferTo(out); } - return filename; + return "/uploads/images" + filename; } } From fde868200be9422e7ea5672acf92a3454cc61825 Mon Sep 17 00:00:00 2001 From: JangIkhwan Date: Thu, 15 Jan 2026 11:36:28 +0900 Subject: [PATCH 07/25] =?UTF-8?q?feat=20:=207=EB=8B=A8=EA=B3=84=20-=20?= =?UTF-8?q?=EA=B2=8C=EC=8B=9C=EA=B8=80=20=EC=9E=91=EC=84=B1=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=EC=97=90=EC=84=9C=20=EC=9D=B4=EB=AF=B8=EC=A7=80?= =?UTF-8?q?=EB=A5=BC=20=EC=97=85=EB=A1=9C=EB=93=9C=ED=95=A0=20=EC=88=98=20?= =?UTF-8?q?=EC=9E=88=EA=B3=A0,=20=EC=9A=94=EC=B2=AD=EC=97=90=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=EA=B0=80=20=EC=97=86=EC=9C=BC=EB=A9=B4=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=EB=AC=B8=EA=B5=AC=EB=A5=BC=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=ED=95=98=EB=8F=84=EB=A1=9D=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../handler/CreateArticleHandler.java | 8 +-- src/main/resources/static/article/error.html | 61 +++++++++++++++++++ src/main/resources/static/article/index.html | 3 +- 3 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 src/main/resources/static/article/error.html diff --git a/src/main/java/webserver/handler/CreateArticleHandler.java b/src/main/java/webserver/handler/CreateArticleHandler.java index 62e03f34d..0badac2d8 100644 --- a/src/main/java/webserver/handler/CreateArticleHandler.java +++ b/src/main/java/webserver/handler/CreateArticleHandler.java @@ -5,10 +5,7 @@ import model.User; import webserver.http.Request; import webserver.http.Response; -import webserver.mvc.Handler; -import webserver.mvc.ModelAndView; -import webserver.mvc.MultipartFile; -import webserver.mvc.RedirectView; +import webserver.mvc.*; import webserver.util.AuthUtil; import java.io.IOException; @@ -37,8 +34,7 @@ public ModelAndView handle(Request request, Response response) { String content = request.getParameter("content"); if(request.getMultipartFiles().size() != 1){ - // todo 게시글 작성폼에서 에러문구 출력하도록 수정 - throw new BadRequestException(); + return new StaticResourceView("/article/error.html"); } MultipartFile multipartFile = request.getMultipartFiles().get(0); diff --git a/src/main/resources/static/article/error.html b/src/main/resources/static/article/error.html new file mode 100644 index 000000000..0c9a62e2e --- /dev/null +++ b/src/main/resources/static/article/error.html @@ -0,0 +1,61 @@ + + + + + + + + + +
+
+ +
    +
  • + 글쓰기 +
  • +
  • +
    + +
    +
  • +
+
+
+

게시글 작성

+
+
+

제목

+ +
+
+

내용

+ +
+ +

이미지는 필수 항목입니다

+ +
+
+
+ + diff --git a/src/main/resources/static/article/index.html b/src/main/resources/static/article/index.html index f53ef1087..1de055f1d 100644 --- a/src/main/resources/static/article/index.html +++ b/src/main/resources/static/article/index.html @@ -25,7 +25,7 @@

게시글 작성

-
+

제목

+
- +
  • From 74a31a8ca27fb8e5209f5bdc2cdb3cafe5bfec7d Mon Sep 17 00:00:00 2001 From: JangIkhwan Date: Thu, 15 Jan 2026 15:10:08 +0900 Subject: [PATCH 13/25] =?UTF-8?q?feat=20:=207=EB=8B=A8=EA=B3=84=20-=20?= =?UTF-8?q?=EC=97=85=EB=A1=9C=EB=93=9C=EB=90=9C=20=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=EC=9D=84=20=EC=9D=91=EB=8B=B5=20=EB=B0=94=EB=94=94=EC=97=90=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=ED=95=98=EB=8A=94=20UploadedFileView=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/webserver/mvc/UploadedFileView.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/main/java/webserver/mvc/UploadedFileView.java diff --git a/src/main/java/webserver/mvc/UploadedFileView.java b/src/main/java/webserver/mvc/UploadedFileView.java new file mode 100644 index 000000000..d54241214 --- /dev/null +++ b/src/main/java/webserver/mvc/UploadedFileView.java @@ -0,0 +1,43 @@ +package webserver.mvc; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import webserver.constant.FileMimeType; +import webserver.exception.StaticResourceNotFoundException; +import webserver.http.Response; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +public class UploadedFileView implements ModelAndView { + private static final Logger logger = LoggerFactory.getLogger(UploadedFileView.class); + private String viewName; + + public UploadedFileView(String viewName) { + this.viewName = viewName; + } + + @Override + public String getViewName() { + return viewName; + } + + @Override + public void render(Response response) { + try{ + String projectRoot = System.getProperty("user.dir"); + String pathname = projectRoot + getViewName(); + + logger.debug("pathname : {}", pathname); + + byte[] body = Files.readAllBytes(new File(pathname).toPath()); + String contentType = FileMimeType.resolveMimeType(getViewName()); + response.setOk(body, contentType); + } + catch (IOException e) { + logger.error("error occurred while reading static resource"); + throw new StaticResourceNotFoundException(); + } + } +} From 2c564ea8921191499e2b66e7a6ca5f03e3f4c597 Mon Sep 17 00:00:00 2001 From: JangIkhwan Date: Thu, 15 Jan 2026 15:10:49 +0900 Subject: [PATCH 14/25] =?UTF-8?q?feat=20:=207=EB=8B=A8=EA=B3=84=20-=20?= =?UTF-8?q?=EC=97=85=EB=A1=9C=EB=93=9C=EB=90=9C=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=EB=A5=BC=20=EC=A0=84=EC=86=A1=ED=95=98=EB=8A=94=20Get?= =?UTF-8?q?ImageHandler=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../webserver/handler/GetImageHandler.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/main/java/webserver/handler/GetImageHandler.java diff --git a/src/main/java/webserver/handler/GetImageHandler.java b/src/main/java/webserver/handler/GetImageHandler.java new file mode 100644 index 000000000..cfbbeb45b --- /dev/null +++ b/src/main/java/webserver/handler/GetImageHandler.java @@ -0,0 +1,19 @@ +package webserver.handler; + +import webserver.exception.StaticResourceNotFoundException; +import webserver.http.Request; +import webserver.http.Response; +import webserver.mvc.Handler; +import webserver.mvc.UploadedFileView; +import webserver.mvc.ModelAndView; + +public class GetImageHandler implements Handler { + @Override + public ModelAndView handle(Request request, Response response) { + String imageFileUrl = request.getParameter("imageUrl"); + if(imageFileUrl == null){ + throw new StaticResourceNotFoundException(); + } + return new UploadedFileView("/uploads/images/" + imageFileUrl); + } +} From ea11a2075e49d5c1fd89307163db8b68310e9c1e Mon Sep 17 00:00:00 2001 From: JangIkhwan Date: Thu, 15 Jan 2026 15:23:40 +0900 Subject: [PATCH 15/25] =?UTF-8?q?feat=20:=207=EB=8B=A8=EA=B3=84=20-=20?= =?UTF-8?q?=EB=A7=88=EC=9D=B4=ED=8E=98=EC=9D=B4=EC=A7=80=EC=97=90=EC=84=9C?= =?UTF-8?q?=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=ED=95=9C=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=EC=9D=98=20=EB=8B=89=EB=84=A4=EC=9E=84=EC=9D=B4=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=ED=8F=BC=EC=97=90=EC=84=9C=20=EB=B3=B4?= =?UTF-8?q?=EC=9D=B4=EB=8F=84=EB=A1=9D=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../webserver/view/MyPageDynamicView.java | 54 +++++++++++++++++++ src/main/resources/static/mypage/index.html | 2 +- 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/main/java/webserver/view/MyPageDynamicView.java diff --git a/src/main/java/webserver/view/MyPageDynamicView.java b/src/main/java/webserver/view/MyPageDynamicView.java new file mode 100644 index 000000000..272df8e1b --- /dev/null +++ b/src/main/java/webserver/view/MyPageDynamicView.java @@ -0,0 +1,54 @@ +package webserver.view; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import webserver.constant.FileMimeType; +import webserver.exception.StaticResourceNotFoundException; +import webserver.http.Response; +import webserver.mvc.ModelAndView; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Map; + +public class MyPageDynamicView implements ModelAndView { + private static final Logger logger = LoggerFactory.getLogger(MyPageDynamicView.class); + private Map model; + private String viewName; + + public MyPageDynamicView(Map model, String viewName) { + this.model = model; + this.viewName = viewName; + } + + @Override + public String getViewName() { + return viewName; + } + + @Override + public void render(Response response) { + try { + Path filePath = Paths.get("./src/main/resources/static" + viewName); + String baseHtml = Files.readString(filePath, StandardCharsets.UTF_8); + + logger.debug("before baseHtml = {} ", baseHtml); + + if (model.containsKey("name")) { + baseHtml = baseHtml.replace("${{name}}", (String) model.get("name")); + } + + logger.debug("after baseHtml = {} ", baseHtml); + + byte[] body = baseHtml.getBytes(StandardCharsets.UTF_8); + String contentType = FileMimeType.resolveMimeType(getViewName()); + response.setOk(body, contentType); + } catch (IOException e) { + logger.error("error occurred while reading static resource"); + throw new StaticResourceNotFoundException(); + } + } +} diff --git a/src/main/resources/static/mypage/index.html b/src/main/resources/static/mypage/index.html index 52bceeb1d..d861edda4 100644 --- a/src/main/resources/static/mypage/index.html +++ b/src/main/resources/static/mypage/index.html @@ -46,7 +46,7 @@

    마이페이지

    닉네임

From 829a5097dde61d2ca48646c62c89d396db11d5b9 Mon Sep 17 00:00:00 2001 From: JangIkhwan Date: Thu, 15 Jan 2026 15:24:11 +0900 Subject: [PATCH 16/25] =?UTF-8?q?feat=20:=207=EB=8B=A8=EA=B3=84=20-=20MyPa?= =?UTF-8?q?geHandler=EC=97=90=EC=84=9C=20=EB=B7=B0=EB=A5=BC=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=ED=95=98=EA=B8=B0=20=EC=9C=84=ED=95=B4=EC=84=9C=20MyP?= =?UTF-8?q?ageHandler=EB=A5=BC=20=EC=82=AC=EC=9A=A9=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/webserver/handler/MyPageHandler.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/java/webserver/handler/MyPageHandler.java b/src/main/java/webserver/handler/MyPageHandler.java index 2ebd88024..5ed119b7f 100644 --- a/src/main/java/webserver/handler/MyPageHandler.java +++ b/src/main/java/webserver/handler/MyPageHandler.java @@ -1,12 +1,13 @@ package webserver.handler; +import model.User; import webserver.http.Request; import webserver.http.Response; -import webserver.mvc.Handler; -import webserver.mvc.RedirectView; -import webserver.mvc.StaticResourceView; +import webserver.mvc.*; +import webserver.view.MyPageDynamicView; import webserver.util.AuthUtil; -import webserver.mvc.ModelAndView; + +import java.util.HashMap; public class MyPageHandler implements Handler { @Override @@ -14,6 +15,11 @@ public ModelAndView handle(Request request, Response response) { if(!AuthUtil.isAuthenticatedUser(request)){ return new RedirectView("/login"); } - return new StaticResourceView("/mypage/index.html"); + + User user = AuthUtil.getAuthenticatedUser(request); + + HashMap model = new HashMap<>(); + model.put("name", user.getName()); + return new MyPageDynamicView(model, "/mypage/index.html"); } } From 300fd3b24d2fa52b08dc79daa594be3633972d23 Mon Sep 17 00:00:00 2001 From: JangIkhwan Date: Thu, 15 Jan 2026 15:26:22 +0900 Subject: [PATCH 17/25] =?UTF-8?q?refactor=20:=207=EB=8B=A8=EA=B3=84=20-=20?= =?UTF-8?q?=EB=B7=B0=20=EA=B4=80=EB=A0=A8=20=ED=81=B4=EB=9E=98=EC=8A=A4?= =?UTF-8?q?=EB=93=A4=EC=9D=84=20view=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/webserver/handler/CreateArticleFormHandler.java | 4 ++-- src/main/java/webserver/handler/CreateArticleHandler.java | 3 +++ src/main/java/webserver/handler/CreateUserHandler.java | 2 +- src/main/java/webserver/handler/GetImageHandler.java | 2 +- src/main/java/webserver/handler/LoginFormHandler.java | 2 +- src/main/java/webserver/handler/LoginHandler.java | 5 ++--- src/main/java/webserver/handler/LogoutHandler.java | 2 +- src/main/java/webserver/handler/MainHandler.java | 2 ++ src/main/java/webserver/handler/MyPageHandler.java | 2 ++ src/main/java/webserver/handler/RegisterFormHandler.java | 2 +- src/main/java/webserver/handler/StaticResourceHandler.java | 2 +- src/main/java/webserver/mvc/RequestHandler.java | 1 + .../java/webserver/{mvc => view}/MainPageDynamicView.java | 3 ++- src/main/java/webserver/{mvc => view}/RedirectView.java | 3 ++- .../java/webserver/{mvc => view}/StaticResourceView.java | 5 +++-- src/main/java/webserver/{mvc => view}/UploadedFileView.java | 3 ++- src/test/java/webserver/handler/LoginHandlerTest.java | 4 ++-- src/test/java/webserver/handler/LogoutHandlerTest.java | 2 +- src/test/java/webserver/handler/MyPageHandlerTest.java | 4 ++-- 19 files changed, 32 insertions(+), 21 deletions(-) rename src/main/java/webserver/{mvc => view}/MainPageDynamicView.java (98%) rename src/main/java/webserver/{mvc => view}/RedirectView.java (86%) rename src/main/java/webserver/{mvc => view}/StaticResourceView.java (90%) rename src/main/java/webserver/{mvc => view}/UploadedFileView.java (95%) diff --git a/src/main/java/webserver/handler/CreateArticleFormHandler.java b/src/main/java/webserver/handler/CreateArticleFormHandler.java index 4fe7c00ed..f6661ad1c 100644 --- a/src/main/java/webserver/handler/CreateArticleFormHandler.java +++ b/src/main/java/webserver/handler/CreateArticleFormHandler.java @@ -4,8 +4,8 @@ import webserver.http.Response; import webserver.mvc.Handler; import webserver.mvc.ModelAndView; -import webserver.mvc.RedirectView; -import webserver.mvc.StaticResourceView; +import webserver.view.RedirectView; +import webserver.view.StaticResourceView; import webserver.util.AuthUtil; public class CreateArticleFormHandler implements Handler { diff --git a/src/main/java/webserver/handler/CreateArticleHandler.java b/src/main/java/webserver/handler/CreateArticleHandler.java index 0badac2d8..88cbf89e6 100644 --- a/src/main/java/webserver/handler/CreateArticleHandler.java +++ b/src/main/java/webserver/handler/CreateArticleHandler.java @@ -7,6 +7,9 @@ import webserver.http.Response; import webserver.mvc.*; import webserver.util.AuthUtil; +import webserver.mvc.ModelAndView; +import webserver.view.RedirectView; +import webserver.view.StaticResourceView; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/webserver/handler/CreateUserHandler.java b/src/main/java/webserver/handler/CreateUserHandler.java index 7278c57cb..cb5c5375a 100644 --- a/src/main/java/webserver/handler/CreateUserHandler.java +++ b/src/main/java/webserver/handler/CreateUserHandler.java @@ -9,7 +9,7 @@ import webserver.http.Response; import webserver.mvc.Handler; import webserver.mvc.ModelAndView; -import webserver.mvc.RedirectView; +import webserver.view.RedirectView; public class CreateUserHandler implements Handler { private static final Logger logger = LoggerFactory.getLogger(CreateUserHandler.class); diff --git a/src/main/java/webserver/handler/GetImageHandler.java b/src/main/java/webserver/handler/GetImageHandler.java index cfbbeb45b..34754914d 100644 --- a/src/main/java/webserver/handler/GetImageHandler.java +++ b/src/main/java/webserver/handler/GetImageHandler.java @@ -4,7 +4,7 @@ import webserver.http.Request; import webserver.http.Response; import webserver.mvc.Handler; -import webserver.mvc.UploadedFileView; +import webserver.view.UploadedFileView; import webserver.mvc.ModelAndView; public class GetImageHandler implements Handler { diff --git a/src/main/java/webserver/handler/LoginFormHandler.java b/src/main/java/webserver/handler/LoginFormHandler.java index caa11a7cb..86a2c2fd8 100644 --- a/src/main/java/webserver/handler/LoginFormHandler.java +++ b/src/main/java/webserver/handler/LoginFormHandler.java @@ -6,7 +6,7 @@ import webserver.http.Response; import webserver.mvc.Handler; import webserver.mvc.ModelAndView; -import webserver.mvc.StaticResourceView; +import webserver.view.StaticResourceView; public class LoginFormHandler implements Handler { private static final Logger logger = LoggerFactory.getLogger(LoginFormHandler.class); diff --git a/src/main/java/webserver/handler/LoginHandler.java b/src/main/java/webserver/handler/LoginHandler.java index bc09b911e..05e83819e 100644 --- a/src/main/java/webserver/handler/LoginHandler.java +++ b/src/main/java/webserver/handler/LoginHandler.java @@ -1,6 +1,5 @@ package webserver.handler; -import db.Database; import db.UserRepository; import model.User; import org.slf4j.Logger; @@ -8,8 +7,8 @@ import webserver.http.Request; import webserver.http.Response; import webserver.mvc.Handler; -import webserver.mvc.RedirectView; -import webserver.mvc.StaticResourceView; +import webserver.view.RedirectView; +import webserver.view.StaticResourceView; import webserver.session.SessionStore; import webserver.mvc.ModelAndView; diff --git a/src/main/java/webserver/handler/LogoutHandler.java b/src/main/java/webserver/handler/LogoutHandler.java index b1bb19a96..8673ecc79 100644 --- a/src/main/java/webserver/handler/LogoutHandler.java +++ b/src/main/java/webserver/handler/LogoutHandler.java @@ -5,7 +5,7 @@ import webserver.http.Request; import webserver.http.Response; import webserver.mvc.Handler; -import webserver.mvc.RedirectView; +import webserver.view.RedirectView; import webserver.util.AuthUtil; import webserver.session.SessionStore; import webserver.mvc.ModelAndView; diff --git a/src/main/java/webserver/handler/MainHandler.java b/src/main/java/webserver/handler/MainHandler.java index 8c3bf361d..8309d1962 100644 --- a/src/main/java/webserver/handler/MainHandler.java +++ b/src/main/java/webserver/handler/MainHandler.java @@ -10,6 +10,8 @@ import webserver.http.Response; import webserver.mvc.*; import webserver.util.AuthUtil; +import webserver.view.MainPageDynamicView; +import webserver.mvc.ModelAndView; import java.util.HashMap; import java.util.List; diff --git a/src/main/java/webserver/handler/MyPageHandler.java b/src/main/java/webserver/handler/MyPageHandler.java index 5ed119b7f..270a28853 100644 --- a/src/main/java/webserver/handler/MyPageHandler.java +++ b/src/main/java/webserver/handler/MyPageHandler.java @@ -4,8 +4,10 @@ import webserver.http.Request; import webserver.http.Response; import webserver.mvc.*; +import webserver.mvc.ModelAndView; import webserver.view.MyPageDynamicView; import webserver.util.AuthUtil; +import webserver.view.RedirectView; import java.util.HashMap; diff --git a/src/main/java/webserver/handler/RegisterFormHandler.java b/src/main/java/webserver/handler/RegisterFormHandler.java index 985ea3032..b00b07d63 100644 --- a/src/main/java/webserver/handler/RegisterFormHandler.java +++ b/src/main/java/webserver/handler/RegisterFormHandler.java @@ -6,7 +6,7 @@ import webserver.http.Response; import webserver.mvc.Handler; import webserver.mvc.ModelAndView; -import webserver.mvc.StaticResourceView; +import webserver.view.StaticResourceView; public class RegisterFormHandler implements Handler { private static final Logger logger = LoggerFactory.getLogger(RegisterFormHandler.class); diff --git a/src/main/java/webserver/handler/StaticResourceHandler.java b/src/main/java/webserver/handler/StaticResourceHandler.java index 98405b20d..11640a10d 100644 --- a/src/main/java/webserver/handler/StaticResourceHandler.java +++ b/src/main/java/webserver/handler/StaticResourceHandler.java @@ -5,7 +5,7 @@ import webserver.http.Request; import webserver.http.Response; import webserver.mvc.Handler; -import webserver.mvc.StaticResourceView; +import webserver.view.StaticResourceView; import webserver.mvc.ModelAndView; public class StaticResourceHandler implements Handler { diff --git a/src/main/java/webserver/mvc/RequestHandler.java b/src/main/java/webserver/mvc/RequestHandler.java index e4355c965..89550e1fd 100644 --- a/src/main/java/webserver/mvc/RequestHandler.java +++ b/src/main/java/webserver/mvc/RequestHandler.java @@ -19,6 +19,7 @@ import webserver.http.Request; import webserver.http.Response; import webserver.session.SessionStore; +import webserver.view.StaticResourceView; public class RequestHandler implements Runnable { private static final Logger logger = LoggerFactory.getLogger(RequestHandler.class); diff --git a/src/main/java/webserver/mvc/MainPageDynamicView.java b/src/main/java/webserver/view/MainPageDynamicView.java similarity index 98% rename from src/main/java/webserver/mvc/MainPageDynamicView.java rename to src/main/java/webserver/view/MainPageDynamicView.java index 955d540c1..71a96d5ca 100644 --- a/src/main/java/webserver/mvc/MainPageDynamicView.java +++ b/src/main/java/webserver/view/MainPageDynamicView.java @@ -1,4 +1,4 @@ -package webserver.mvc; +package webserver.view; import model.Article; import org.slf4j.Logger; @@ -6,6 +6,7 @@ import webserver.constant.FileMimeType; import webserver.exception.StaticResourceNotFoundException; import webserver.http.Response; +import webserver.mvc.ModelAndView; import java.io.IOException; import java.nio.charset.StandardCharsets; diff --git a/src/main/java/webserver/mvc/RedirectView.java b/src/main/java/webserver/view/RedirectView.java similarity index 86% rename from src/main/java/webserver/mvc/RedirectView.java rename to src/main/java/webserver/view/RedirectView.java index 1fd70316e..53b9711e2 100644 --- a/src/main/java/webserver/mvc/RedirectView.java +++ b/src/main/java/webserver/view/RedirectView.java @@ -1,6 +1,7 @@ -package webserver.mvc; +package webserver.view; import webserver.http.Response; +import webserver.mvc.ModelAndView; public class RedirectView implements ModelAndView { private String viewName; diff --git a/src/main/java/webserver/mvc/StaticResourceView.java b/src/main/java/webserver/view/StaticResourceView.java similarity index 90% rename from src/main/java/webserver/mvc/StaticResourceView.java rename to src/main/java/webserver/view/StaticResourceView.java index a51b56727..43b57505c 100644 --- a/src/main/java/webserver/mvc/StaticResourceView.java +++ b/src/main/java/webserver/view/StaticResourceView.java @@ -1,16 +1,17 @@ -package webserver.mvc; +package webserver.view; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import webserver.constant.FileMimeType; import webserver.exception.StaticResourceNotFoundException; import webserver.http.Response; +import webserver.mvc.ModelAndView; import java.io.File; import java.io.IOException; import java.nio.file.Files; -public class StaticResourceView implements ModelAndView{ +public class StaticResourceView implements ModelAndView { private static final Logger logger = LoggerFactory.getLogger(StaticResourceView.class); private String viewName; diff --git a/src/main/java/webserver/mvc/UploadedFileView.java b/src/main/java/webserver/view/UploadedFileView.java similarity index 95% rename from src/main/java/webserver/mvc/UploadedFileView.java rename to src/main/java/webserver/view/UploadedFileView.java index d54241214..a204fd635 100644 --- a/src/main/java/webserver/mvc/UploadedFileView.java +++ b/src/main/java/webserver/view/UploadedFileView.java @@ -1,10 +1,11 @@ -package webserver.mvc; +package webserver.view; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import webserver.constant.FileMimeType; import webserver.exception.StaticResourceNotFoundException; import webserver.http.Response; +import webserver.mvc.ModelAndView; import java.io.File; import java.io.IOException; diff --git a/src/test/java/webserver/handler/LoginHandlerTest.java b/src/test/java/webserver/handler/LoginHandlerTest.java index f4ce6f76f..fa7c2dc1e 100644 --- a/src/test/java/webserver/handler/LoginHandlerTest.java +++ b/src/test/java/webserver/handler/LoginHandlerTest.java @@ -7,8 +7,8 @@ import webserver.http.Request; import webserver.http.Response; import webserver.mvc.ModelAndView; -import webserver.mvc.RedirectView; -import webserver.mvc.StaticResourceView; +import webserver.view.RedirectView; +import webserver.view.StaticResourceView; import webserver.session.SessionStore; import java.util.HashMap; diff --git a/src/test/java/webserver/handler/LogoutHandlerTest.java b/src/test/java/webserver/handler/LogoutHandlerTest.java index f2d28c4af..9fc1f632e 100644 --- a/src/test/java/webserver/handler/LogoutHandlerTest.java +++ b/src/test/java/webserver/handler/LogoutHandlerTest.java @@ -6,7 +6,7 @@ import webserver.http.Request; import webserver.http.Response; import webserver.mvc.ModelAndView; -import webserver.mvc.RedirectView; +import webserver.view.RedirectView; import webserver.session.SessionStore; import java.util.HashMap; diff --git a/src/test/java/webserver/handler/MyPageHandlerTest.java b/src/test/java/webserver/handler/MyPageHandlerTest.java index d954ac908..fba49f244 100644 --- a/src/test/java/webserver/handler/MyPageHandlerTest.java +++ b/src/test/java/webserver/handler/MyPageHandlerTest.java @@ -6,8 +6,8 @@ import webserver.http.Request; import webserver.http.Response; import webserver.mvc.ModelAndView; -import webserver.mvc.RedirectView; -import webserver.mvc.StaticResourceView; +import webserver.view.RedirectView; +import webserver.view.StaticResourceView; import webserver.session.SessionStore; import java.util.HashMap; From 4c660189d1b175a6a01c4a01a74fcc6938f41f5f Mon Sep 17 00:00:00 2001 From: JangIkhwan Date: Thu, 15 Jan 2026 15:40:30 +0900 Subject: [PATCH 18/25] =?UTF-8?q?feat=20:=207=EB=8B=A8=EA=B3=84=20-=20User?= =?UTF-8?q?=20=EC=97=94=ED=8B=B0=ED=8B=B0=EC=97=90=20imageUrl=20=ED=95=84?= =?UTF-8?q?=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 --- src/main/java/model/User.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/java/model/User.java b/src/main/java/model/User.java index c4593aa3c..0fdcce95e 100644 --- a/src/main/java/model/User.java +++ b/src/main/java/model/User.java @@ -7,12 +7,14 @@ public class User { private String password; private String name; private String email; + private String imageUrl; - public User(Long id, String password, String name, String email) { + public User(Long id, String password, String name, String email, String imageUrl) { this.id = id; this.password = password; this.name = name; this.email = email; + this.imageUrl = imageUrl; } public User(String password, String name, String email) { @@ -51,4 +53,15 @@ public void setId(Long id) { public String toString() { return "User [userId=" + id + ", password=" + password + ", name=" + name + ", email=" + email + "]"; } + + public void changeProfileImage(String imageUrl) { + if(imageUrl == null){ + throw new BusinessException(); + } + this.imageUrl = imageUrl; + } + + public String getImageUrl() { + return imageUrl; + } } From f74c7538cec40228c56cc8bb6659023c90a73ae1 Mon Sep 17 00:00:00 2001 From: JangIkhwan Date: Thu, 15 Jan 2026 18:41:35 +0900 Subject: [PATCH 19/25] =?UTF-8?q?feat=20:=207=EB=8B=A8=EA=B3=84=20-=20User?= =?UTF-8?q?Repository=20=EC=BF=BC=EB=A6=AC=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EB=B0=8F=20update=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/db/UserRepository.java | 1 + src/main/java/db/UserRepositoryImpl.java | 43 +++++++++++++++++++++--- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/main/java/db/UserRepository.java b/src/main/java/db/UserRepository.java index ca9d999bc..c31d4365c 100644 --- a/src/main/java/db/UserRepository.java +++ b/src/main/java/db/UserRepository.java @@ -9,4 +9,5 @@ public interface UserRepository { User save(User user); Optional findByEmail(String email); Optional findById(Long id); + User update(User user); } diff --git a/src/main/java/db/UserRepositoryImpl.java b/src/main/java/db/UserRepositoryImpl.java index f215c6b16..90bd0ad39 100644 --- a/src/main/java/db/UserRepositoryImpl.java +++ b/src/main/java/db/UserRepositoryImpl.java @@ -14,7 +14,7 @@ public class UserRepositoryImpl implements UserRepository { private static final Logger logger = LoggerFactory.getLogger(UserRepository.class); public User save(User user) { - String sql = "insert into user_tbl(password, nickname, email) values(?, ?, ?)"; + String sql = "insert into user_tbl(password, nickname, email, image_url) values(?, ?, ?)"; try ( Connection con = DriverManager.getConnection(JDBC_URL, USER, PASSWORD); @@ -25,6 +25,7 @@ public User save(User user) { pstmt.setString(1, user.getPassword()); pstmt.setString(2, user.getName()); pstmt.setString(3, user.getEmail()); + pstmt.setString(4, user.getImageUrl()); pstmt.executeUpdate(); @@ -43,7 +44,7 @@ public User save(User user) { } public Optional findByEmail(String email) { - String sql = "select id, password, nickname from user_tbl where email = ?"; + String sql = "select id, password, nickname, image_url from user_tbl where email = ?"; try ( Connection con = DriverManager.getConnection(JDBC_URL, USER, PASSWORD); @@ -61,7 +62,8 @@ public Optional findByEmail(String email) { long id = rs.getLong("id"); String password = rs.getString("password"); String nickname = rs.getString("nickname"); - user = new User(id, password, nickname, email); + String imageUrl = rs.getString("image_url"); + user = new User(id, password, nickname, email, imageUrl); } return Optional.of(user); @@ -73,7 +75,7 @@ public Optional findByEmail(String email) { @Override public Optional findById(Long id) { - String sql = "select password, nickname, email from user_tbl where id = ?"; + String sql = "select password, nickname, email, image_url from user_tbl where id = ?"; try ( Connection con = DriverManager.getConnection(JDBC_URL, USER, PASSWORD); @@ -91,7 +93,8 @@ public Optional findById(Long id) { String password = rs.getString("password"); String nickname = rs.getString("nickname"); String email = rs.getString("email"); - user = new User(id, password, nickname, email); + String imageUrl = rs.getString("image_url"); + user = new User(id, password, nickname, email, imageUrl); } return Optional.of(user); @@ -100,4 +103,34 @@ public Optional findById(Long id) { throw new RuntimeException(e); } } + + @Override + public User update(User user) { + String sql = "update user_tbl set password = ?, nickname = ?, email = ?, image_url = ? where id = ?"; + + try ( + Connection con = DriverManager.getConnection(JDBC_URL, USER, PASSWORD); + PreparedStatement pstmt = con.prepareStatement(sql); + ) { + logger.debug("DB 연결 성공"); + + pstmt.setString(1, user.getPassword()); + pstmt.setString(2, user.getName()); + pstmt.setString(3, user.getEmail()); + pstmt.setString(4, user.getImageUrl()); + pstmt.setLong(5, user.getId()); + + int updatedRows = pstmt.executeUpdate(); + + if (updatedRows == 0) { + throw new SQLException("업데이트 실패: 해당 id 없음"); + } + + return user; + } catch (SQLException e) { + logger.error("DB 업데이트 실패", e); + throw new RuntimeException(e); + } + } + } \ No newline at end of file From 2a8af7d33034e03cb5932570fbf387b742c79b67 Mon Sep 17 00:00:00 2001 From: JangIkhwan Date: Thu, 15 Jan 2026 18:42:09 +0900 Subject: [PATCH 20/25] =?UTF-8?q?feat=20:=207=EB=8B=A8=EA=B3=84=20-=20Mult?= =?UTF-8?q?ipartFile=20=EA=B4=80=EB=A0=A8=20=EC=9C=A0=ED=8B=B8=EB=A6=AC?= =?UTF-8?q?=ED=8B=B0=20MultipartFileUtil=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../webserver/util/MultipartFileUtil.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/main/java/webserver/util/MultipartFileUtil.java diff --git a/src/main/java/webserver/util/MultipartFileUtil.java b/src/main/java/webserver/util/MultipartFileUtil.java new file mode 100644 index 000000000..2ff9e736d --- /dev/null +++ b/src/main/java/webserver/util/MultipartFileUtil.java @@ -0,0 +1,39 @@ +package webserver.util; + +import webserver.mvc.MultipartFile; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.UUID; + +public class MultipartFileUtil { + public static String saveFile(String directoryPath, MultipartFile multipartFile) throws IOException { + if (directoryPath == null || directoryPath.isBlank()) { + throw new IllegalArgumentException(); + } + + String filename = UUID.randomUUID() + multipartFile.getFilename(); + + Path uploadDir = Paths.get(System.getProperty("user.dir")) + .resolve(directoryPath); + + Files.createDirectories(uploadDir); + + Path target = uploadDir.resolve(filename); + + try (InputStream in = multipartFile.getInputStream(); + OutputStream out = Files.newOutputStream(target, + StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING)) { + + in.transferTo(out); + } + + return directoryPath + "/" + filename; + } +} From 4b0bacba423291df1f6dd13559fa4c6745f4f7d8 Mon Sep 17 00:00:00 2001 From: JangIkhwan Date: Thu, 15 Jan 2026 18:43:26 +0900 Subject: [PATCH 21/25] =?UTF-8?q?feat=20:=207=EB=8B=A8=EA=B3=84=20-=20?= =?UTF-8?q?=ED=94=84=EB=A1=9C=ED=95=84=20=EC=9D=B4=EB=AF=B8=EC=A7=80?= =?UTF-8?q?=EB=A5=BC=20=EC=88=98=EC=A0=95=ED=95=98=EB=8A=94=20PatchMyPageH?= =?UTF-8?q?andler=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../webserver/handler/PatchMyPageHandler.java | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/main/java/webserver/handler/PatchMyPageHandler.java diff --git a/src/main/java/webserver/handler/PatchMyPageHandler.java b/src/main/java/webserver/handler/PatchMyPageHandler.java new file mode 100644 index 000000000..4947b7eba --- /dev/null +++ b/src/main/java/webserver/handler/PatchMyPageHandler.java @@ -0,0 +1,52 @@ +package webserver.handler; + +import db.UserRepository; +import model.User; +import webserver.exception.BusinessException; +import webserver.http.Request; +import webserver.http.Response; +import webserver.mvc.Handler; +import webserver.mvc.ModelAndView; +import webserver.mvc.MultipartFile; +import webserver.util.AuthUtil; +import webserver.util.MultipartFileUtil; +import webserver.view.RedirectView; + +import java.io.IOException; + +public class PatchMyPageHandler implements Handler { + private final UserRepository userRepository; + + public PatchMyPageHandler(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @Override + public ModelAndView handle(Request request, Response response) { + if (!AuthUtil.isAuthenticatedUser(request)) { + return new RedirectView("/login"); + } + + User cachedUser = AuthUtil.getAuthenticatedUser(request); + User userByEmail = userRepository.findByEmail(cachedUser.getEmail()) + .orElseThrow(() -> new BusinessException()); + + if (request.getMultipartFiles().size() != 1) { + return new RedirectView("/mypage"); + } + MultipartFile multipartFile = request.getMultipartFiles().get(0); + + String imageUrl = null; + try { + imageUrl = MultipartFileUtil.saveFile("uploads/images", multipartFile); + } catch (IOException e) { + throw new RuntimeException(e); + } + + userByEmail.changeProfileImage(imageUrl); + + userRepository.update(userByEmail); + + return new RedirectView("/mypage"); + } +} From 29cff5f3eae21a1252833f2cd99af49c4b884d89 Mon Sep 17 00:00:00 2001 From: JangIkhwan Date: Thu, 15 Jan 2026 18:43:47 +0900 Subject: [PATCH 22/25] =?UTF-8?q?feat=20:=207=EB=8B=A8=EA=B3=84=20-=20Patc?= =?UTF-8?q?hMyPageHandler=EB=A5=BC=20routingTable=EC=97=90=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/webserver/mvc/RequestHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/webserver/mvc/RequestHandler.java b/src/main/java/webserver/mvc/RequestHandler.java index 89550e1fd..6b0180d58 100644 --- a/src/main/java/webserver/mvc/RequestHandler.java +++ b/src/main/java/webserver/mvc/RequestHandler.java @@ -38,7 +38,7 @@ public class RequestHandler implements Runnable { routingTable.add(new SimpleRouting("/create", Map.of("POST", new CreateUserHandler(userRepository)))); routingTable.add(new SimpleRouting("/login", Map.of("GET", new LoginFormHandler(), "POST", new LoginHandler(userRepository)))); routingTable.add(new SimpleRouting("/logout", Map.of("POST", new LogoutHandler()))); - routingTable.add(new SimpleRouting("/mypage", Map.of("GET", new MyPageHandler()))); + routingTable.add(new SimpleRouting("/mypage", Map.of("GET", new MyPageHandler(userRepository), "PATCH", new PatchMyPageHandler(userRepository)))); routingTable.add(new SimpleRouting("/article/create-form", Map.of("GET", new CreateArticleFormHandler()))); routingTable.add(new SimpleRouting("/article", Map.of("POST", new CreateArticleHandler(articleRepository)))); routingTable.add(new PathVariableRouting("/uploads/images/{imageUrl}", Map.of("GET", new GetImageHandler()))); From 16273a4b148c345c5cb5f5362d022e45bc0a2a62 Mon Sep 17 00:00:00 2001 From: JangIkhwan Date: Thu, 15 Jan 2026 18:44:38 +0900 Subject: [PATCH 23/25] =?UTF-8?q?feat=20:=207=EB=8B=A8=EA=B3=84=20-=20?= =?UTF-8?q?=EB=A7=88=EC=9D=B4=ED=8E=98=EC=9D=B4=EC=A7=80=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=EC=97=90=EC=84=9C=20=ED=94=84=EB=A1=9C=ED=95=84=20?= =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=EA=B0=80=20=EB=B3=B4=EC=9D=B4?= =?UTF-8?q?=EA=B3=A0,=20=EC=88=98=EC=A0=95=ED=95=A0=20=EC=88=98=20?= =?UTF-8?q?=EC=9E=88=EB=8F=84=EB=A1=9D=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../webserver/view/MyPageDynamicView.java | 7 + src/main/resources/static/global.css | 8 + src/main/resources/static/mypage/index.html | 195 +++++++++++------- 3 files changed, 138 insertions(+), 72 deletions(-) diff --git a/src/main/java/webserver/view/MyPageDynamicView.java b/src/main/java/webserver/view/MyPageDynamicView.java index 272df8e1b..b97c58071 100644 --- a/src/main/java/webserver/view/MyPageDynamicView.java +++ b/src/main/java/webserver/view/MyPageDynamicView.java @@ -41,6 +41,13 @@ public void render(Response response) { baseHtml = baseHtml.replace("${{name}}", (String) model.get("name")); } + if (model.containsKey("profile_image")) { + baseHtml = baseHtml.replace("${{profile_image}}", (String) model.get("profile_image")); + } + else{ + baseHtml = baseHtml.replace("${{profile_image}}", ""); + } + logger.debug("after baseHtml = {} ", baseHtml); byte[] body = baseHtml.getBytes(StandardCharsets.UTF_8); diff --git a/src/main/resources/static/global.css b/src/main/resources/static/global.css index d9158fc84..e3d4f9e7b 100644 --- a/src/main/resources/static/global.css +++ b/src/main/resources/static/global.css @@ -157,6 +157,14 @@ height: 200px; border-radius: 9999px; background: #d9d9d9; + overflow: hidden; +} + +.profile_image .profile { + width: 100%; + height: 100%; + object-fit: cover; + display: block; } .profile_container { diff --git a/src/main/resources/static/mypage/index.html b/src/main/resources/static/mypage/index.html index d861edda4..4cea7558f 100644 --- a/src/main/resources/static/mypage/index.html +++ b/src/main/resources/static/mypage/index.html @@ -1,83 +1,134 @@ - - - - - - - -
-
- + + + + + + + +
+
+ -
-
+
+

마이페이지

-
-
- -
-
-
-
수정
-
-
-
-
삭제
-
-
-
-
-
-

닉네임

- -
-
-

비밀번호

- -
-
-

비밀번호 확인

- +
+
+ +
+
+
+
수정
+
+
+
+
삭제
+
+
- + + +
+

닉네임

+ +
+
+

비밀번호

+ +
+
+

비밀번호 확인

+ +
+
+ type="button" + > + 변경사항 저장 + +
+
- +
+ + From cd5c12e8543ae86187c92dab4615fb1152cd7584 Mon Sep 17 00:00:00 2001 From: JangIkhwan Date: Thu, 15 Jan 2026 18:45:04 +0900 Subject: [PATCH 24/25] =?UTF-8?q?feat=20:=207=EB=8B=A8=EA=B3=84=20-=20MyPa?= =?UTF-8?q?geHandler=EC=97=90=EC=84=9C=20=EB=B7=B0=EC=97=90=20=EC=A0=84?= =?UTF-8?q?=EB=8B=AC=ED=95=98=EB=8A=94=20=EC=A0=95=EB=B3=B4=EB=A5=BC=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/webserver/handler/MyPageHandler.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/webserver/handler/MyPageHandler.java b/src/main/java/webserver/handler/MyPageHandler.java index 270a28853..a33ee8bf7 100644 --- a/src/main/java/webserver/handler/MyPageHandler.java +++ b/src/main/java/webserver/handler/MyPageHandler.java @@ -1,6 +1,8 @@ package webserver.handler; +import db.UserRepository; import model.User; +import webserver.exception.BusinessException; import webserver.http.Request; import webserver.http.Response; import webserver.mvc.*; @@ -12,16 +14,29 @@ import java.util.HashMap; public class MyPageHandler implements Handler { + private final UserRepository userRepository; + + public MyPageHandler(UserRepository userRepository) { + this.userRepository = userRepository; + } + @Override public ModelAndView handle(Request request, Response response) { if(!AuthUtil.isAuthenticatedUser(request)){ return new RedirectView("/login"); } - User user = AuthUtil.getAuthenticatedUser(request); + User cachedUser = AuthUtil.getAuthenticatedUser(request); + + User user = userRepository.findByEmail(cachedUser.getEmail()) + .orElseThrow(() -> new BusinessException()); HashMap model = new HashMap<>(); model.put("name", user.getName()); + String imageUrl = user.getImageUrl(); + if(imageUrl != null){ + model.put("profile_image", imageUrl); + } return new MyPageDynamicView(model, "/mypage/index.html"); } } From ab229749c8b42954b1931e5b28ac2d6618d3b1d1 Mon Sep 17 00:00:00 2001 From: JangIkhwan Date: Thu, 15 Jan 2026 18:45:32 +0900 Subject: [PATCH 25/25] =?UTF-8?q?refactor=20:=207=EB=8B=A8=EA=B3=84=20-=20?= =?UTF-8?q?CreateArticleHandler=EC=97=90=EC=84=9C=20MultipartFileUtil?= =?UTF-8?q?=EC=9D=84=20=EC=82=AC=EC=9A=A9=ED=95=98=EB=8F=84=EB=A1=9D=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 --- .../handler/CreateArticleHandler.java | 31 ++----------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/src/main/java/webserver/handler/CreateArticleHandler.java b/src/main/java/webserver/handler/CreateArticleHandler.java index 88cbf89e6..bffc8c2ef 100644 --- a/src/main/java/webserver/handler/CreateArticleHandler.java +++ b/src/main/java/webserver/handler/CreateArticleHandler.java @@ -8,17 +8,11 @@ import webserver.mvc.*; import webserver.util.AuthUtil; import webserver.mvc.ModelAndView; +import webserver.util.MultipartFileUtil; import webserver.view.RedirectView; import webserver.view.StaticResourceView; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; -import java.util.UUID; public class CreateArticleHandler implements Handler { private final ArticleRepository articleRepository; @@ -44,7 +38,7 @@ public ModelAndView handle(Request request, Response response) { String imageUrl = null; try { - imageUrl = saveFile(multipartFile); + imageUrl = MultipartFileUtil.saveFile("uploads/images", multipartFile); } catch (IOException e) { throw new RuntimeException(e); } @@ -53,25 +47,4 @@ public ModelAndView handle(Request request, Response response) { return new RedirectView("/"); } - - private String saveFile(MultipartFile multipartFile) throws IOException { - InputStream in = multipartFile.getInputStream(); - String filename = UUID.randomUUID().toString() + multipartFile.getFilename(); - String projectRoot = System.getProperty("user.dir"); - Path uploadDir = Paths.get(projectRoot, "uploads", "images"); - - Files.createDirectories(uploadDir); - - Path target = uploadDir.resolve(filename); - - try (OutputStream out = Files.newOutputStream( - target, - StandardOpenOption.CREATE, - StandardOpenOption.TRUNCATE_EXISTING)) { - - in.transferTo(out); - } - - return "/uploads/images" + filename; - } }