Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
2a60d42
feat : 7단계 - Article에 imageUrl 필드 추가
JangIkhwan Jan 15, 2026
4dbd878
feat : 7단계 - ArticleRepositoryImpl에서 쿼리 메서드 수정
JangIkhwan Jan 15, 2026
b005dfa
feat : 7단계 - CreateArticleHandler에서 이미지를 저장하는 로직 추가
JangIkhwan Jan 15, 2026
ab6df93
feat : 7단계 - RequestHandler에서 BadRequestException 발생 시에 에러페이지를 보여주도록 …
JangIkhwan Jan 15, 2026
79fd1fa
fix : 7단계 - ArticleRepositoryImpl에서 잘못된 로직 수정
JangIkhwan Jan 15, 2026
4726225
fix : 7단계 - saveFile에서 반환하는 파일의 url을 수정
JangIkhwan Jan 15, 2026
fde8682
feat : 7단계 - 게시글 작성 화면에서 이미지를 업로드할 수 있고, 요청에 이미지가 없으면 에러 문구를 출력하도록 구현
JangIkhwan Jan 15, 2026
3f87d2f
chore : 7단계 - gitignore 수정
JangIkhwan Jan 15, 2026
760a0f3
feat : 7단계 - 핸들러 라우팅을 위한 Routing 인터페이스와 구현체 추가
JangIkhwan Jan 15, 2026
2a2d596
fix : 7단계 - 요청에서 path를 파싱할 때 한글이 깨지지 않도록 디코딩 적용
JangIkhwan Jan 15, 2026
7c6df7e
refactor : 7단계 - Routing을 이용해서 핸들러를 찾도록 resolveHandler 수정
JangIkhwan Jan 15, 2026
d722124
feat : 7단계 - 메인페이지에 게시글 이미지가 보이도록 구현
JangIkhwan Jan 15, 2026
74a31a8
feat : 7단계 - 업로드된 파일을 응답 바디에 추가하는 UploadedFileView 작성
JangIkhwan Jan 15, 2026
2c564ea
feat : 7단계 - 업로드된 이미지를 전송하는 GetImageHandler 작성
JangIkhwan Jan 15, 2026
ea11a20
feat : 7단계 - 마이페이지에서 로그인한 사용자의 닉네임이 변경 폼에서 보이도록 구현
JangIkhwan Jan 15, 2026
829a509
feat : 7단계 - MyPageHandler에서 뷰를 생성하기 위해서 MyPageHandler를 사용하도록 수정
JangIkhwan Jan 15, 2026
300fd3b
refactor : 7단계 - 뷰 관련 클래스들을 view 패키지로 이동
JangIkhwan Jan 15, 2026
4c66018
feat : 7단계 - User 엔티티에 imageUrl 필드 추가
JangIkhwan Jan 15, 2026
f74c753
feat : 7단계 - UserRepository 쿼리 수정 및 update 메서드 추가
JangIkhwan Jan 15, 2026
2a8af7d
feat : 7단계 - MultipartFile 관련 유틸리티 MultipartFileUtil 작성
JangIkhwan Jan 15, 2026
4b0bacb
feat : 7단계 - 프로필 이미지를 수정하는 PatchMyPageHandler 작성
JangIkhwan Jan 15, 2026
29cff5f
feat : 7단계 - PatchMyPageHandler를 routingTable에 추가
JangIkhwan Jan 15, 2026
16273a4
feat : 7단계 - 마이페이지 화면에서 프로필 이미지가 보이고, 수정할 수 있도록 기능 구현
JangIkhwan Jan 15, 2026
cd5c12e
feat : 7단계 - MyPageHandler에서 뷰에 전달하는 정보를 수정
JangIkhwan Jan 15, 2026
ab22974
refactor : 7단계 - CreateArticleHandler에서 MultipartFileUtil을 사용하도록 수정
JangIkhwan Jan 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,5 @@ gradle-app.setting
*.hprof

# End of https://www.toptal.com/developers/gitignore/api/gradle,intellij,java,macos

**/uploads
8 changes: 5 additions & 3 deletions src/main/java/db/ArticleRepositoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@ 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, image_url) values(?, ?, ?, ?)";
try (
Connection con = DriverManager.getConnection(JDBC_URL, USER, PASSWORD);
PreparedStatement pstmt = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
) {
pstmt.setLong(1, article.getCreatorId());
pstmt.setString(2, article.getTitle());
pstmt.setString(3, article.getContent());
pstmt.setString(4, article.getImageUrl());

pstmt.executeUpdate();

Expand All @@ -41,7 +42,7 @@ public Article save(Article article) {

@Override
public List<Article> 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);
Expand All @@ -58,7 +59,8 @@ public List<Article> 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;
Expand Down
1 change: 1 addition & 0 deletions src/main/java/db/UserRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ public interface UserRepository {
User save(User user);
Optional<User> findByEmail(String email);
Optional<User> findById(Long id);
User update(User user);
}
43 changes: 38 additions & 5 deletions src/main/java/db/UserRepositoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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();

Expand All @@ -43,7 +44,7 @@ public User save(User user) {
}

public Optional<User> 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);
Expand All @@ -61,7 +62,8 @@ public Optional<User> 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);

Expand All @@ -73,7 +75,7 @@ public Optional<User> findByEmail(String email) {

@Override
public Optional<User> 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);
Expand All @@ -91,7 +93,8 @@ public Optional<User> 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);

Expand All @@ -100,4 +103,34 @@ public Optional<User> 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);
}
}

}
11 changes: 9 additions & 2 deletions src/main/java/model/Article.java
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -40,6 +43,10 @@ public String getContent() {
return content;
}

public String getImageUrl() {
return imageUrl;
}

public void setId(Long id) {
this.id = id;
}
Expand Down
15 changes: 14 additions & 1 deletion src/main/java/model/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
}
4 changes: 2 additions & 2 deletions src/main/java/webserver/handler/CreateArticleFormHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
25 changes: 21 additions & 4 deletions src/main/java/webserver/handler/CreateArticleHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@
import model.User;
import webserver.http.Request;
import webserver.http.Response;
import webserver.mvc.Handler;
import webserver.mvc.ModelAndView;
import webserver.mvc.RedirectView;
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;

public class CreateArticleHandler implements Handler {
private final ArticleRepository articleRepository;
Expand All @@ -26,7 +30,20 @@ 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){
return new StaticResourceView("/article/error.html");
}

MultipartFile multipartFile = request.getMultipartFiles().get(0);

String imageUrl = null;
try {
imageUrl = MultipartFileUtil.saveFile("uploads/images", multipartFile);
} catch (IOException e) {
throw new RuntimeException(e);
}

articleRepository.save(new Article(user.getId(), title, content, imageUrl));

return new RedirectView("/");
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/webserver/handler/CreateUserHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/webserver/handler/GetImageHandler.java
Original file line number Diff line number Diff line change
@@ -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.view.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);
}
}
2 changes: 1 addition & 1 deletion src/main/java/webserver/handler/LoginFormHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 2 additions & 3 deletions src/main/java/webserver/handler/LoginHandler.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package webserver.handler;

import db.Database;
import db.UserRepository;
import model.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/webserver/handler/LogoutHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/webserver/handler/MainHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
33 changes: 28 additions & 5 deletions src/main/java/webserver/handler/MyPageHandler.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,42 @@
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.RedirectView;
import webserver.mvc.StaticResourceView;
import webserver.util.AuthUtil;
import webserver.mvc.*;
import webserver.mvc.ModelAndView;
import webserver.view.MyPageDynamicView;
import webserver.util.AuthUtil;
import webserver.view.RedirectView;

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");
}
return new StaticResourceView("/mypage/index.html");

User cachedUser = AuthUtil.getAuthenticatedUser(request);

User user = userRepository.findByEmail(cachedUser.getEmail())
.orElseThrow(() -> new BusinessException());

HashMap<String, Object> 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");
}
}
Loading