Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 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
77686d2
feat : 7단계 - 마이페이지에 닉네임 비밀번호 변경 기능 구현
JangIkhwan Jan 16, 2026
410dae4
feat : 7단계 - 메인화면에서 사용자 프로필 이미지 보이게 기능 구현
JangIkhwan Jan 16, 2026
640ad3b
feat : 7단계 - 프로필 이미지 삭제 기능 구현
JangIkhwan Jan 16, 2026
f36cff1
fix : 7단계 - 프로필 이미지가 없는 유저의 글을 메인화면에 보일 수 있도록 수정
JangIkhwan Jan 16, 2026
2bb37ec
chore : 7단계 - CreateArticleHandler에 로깅 추가
JangIkhwan Jan 16, 2026
3512102
feat : 7단계 - 글 작성 화면에서 이미지는 필수 파라미터로 지정
JangIkhwan Jan 16, 2026
03fdba3
feat : 7단계 - LoginHandler에 로깅 추가
JangIkhwan Jan 16, 2026
37e2e43
feat : 7단계 - 로그인 실패 문구를 아이디가 틀렸을 경우와 비밀번호가 틀렸을 경우로 분리
JangIkhwan Jan 16, 2026
8660909
feat : 7단계 - 회원가입 시 잘못된 입력이 들어오면 에러를 띄우도록 수정
JangIkhwan Jan 16, 2026
545f0d9
feat : 7단계 - Article에 likeCount 필드 추가
JangIkhwan Jan 16, 2026
e277a02
feat : 7단계 - ArticleRepositoryImpl의 조회 메서드에서 likeCount를 조회하도록 수정
JangIkhwan Jan 16, 2026
f28887f
feat : 7단계 - ArticleRepository에 메서드 추가
JangIkhwan Jan 16, 2026
488246c
feat : 7단계 - Article에 메서드 추가
JangIkhwan Jan 16, 2026
a1b86a4
feat : 7단계 - IncreaseArticleLikeHandler 구현
JangIkhwan Jan 16, 2026
80b2211
feat : 7단계 - 메인 페이지에서 좋아요수를 출력하고 좋아요 요청을 보낼 수 있도록 페이지 수정
JangIkhwan Jan 16, 2026
9fdcb12
feat : 7단계 - routingTable에 IncreaseArticleLikeHandler 등록
JangIkhwan Jan 16, 2026
ea878f5
feat : 7단계 - 게시글에서 좋아요 추가 기능 구현
JangIkhwan Jan 16, 2026
0c24895
feat : 7단계 - 게시글 이동 기능 및 게시글 존재 여부에 따라 댓글 작성 버튼 표시 기능 구현
JangIkhwan Jan 16, 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
12 changes: 12 additions & 0 deletions src/main/java/db/ArticleRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,20 @@
import model.Article;

import java.util.List;
import java.util.Optional;

public interface ArticleRepository {
Article save(Article article);

List<Article> findTopNLessThanByIdDecreasingOrder(int limit, long id);

Optional<Article> findById(long id);

void update(Article article);

Optional<Article> findLatest();

Optional<Article> findNext(Long id);

Optional<Article> findPrev(Long id);
}
165 changes: 162 additions & 3 deletions src/main/java/db/ArticleRepositoryImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class ArticleRepositoryImpl implements ArticleRepository {
private static final String JDBC_URL = "jdbc:h2:tcp://localhost/~/h2-db/was-be";
Expand All @@ -15,14 +16,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 +43,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, like_count from article_tbl where id < ? order by id desc limit ?";

try (
Connection con = DriverManager.getConnection(JDBC_URL, USER, PASSWORD);
Expand All @@ -58,7 +60,9 @@ 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");
long likeCount = rs.getLong("like_count");
articles.add(new Article(articleId, creatorId, title, content, imageUrl, likeCount));
}
}
return articles;
Expand All @@ -67,4 +71,159 @@ public List<Article> findTopNLessThanByIdDecreasingOrder(int limit, long id) {
throw new RuntimeException(e);
}
}

@Override
public Optional<Article> findById(long id) {
String sql = "select id, creatorId, title, content, image_url, like_count " +
"from article_tbl where id = ?";

try (
Connection con = DriverManager.getConnection(JDBC_URL, USER, PASSWORD);
PreparedStatement pstmt = con.prepareStatement(sql);
) {
pstmt.setLong(1, id);

try (ResultSet rs = pstmt.executeQuery()) {
if (!rs.next()) {
return Optional.empty();
}

Article article = new Article(
rs.getLong("id"),
rs.getLong("creatorId"),
rs.getString("title"),
rs.getString("content"),
rs.getString("image_url"),
rs.getLong("like_count")
);

return Optional.of(article);
}
} catch (SQLException e) {
logger.error("Article 조회 실패 id={}", id, e);
throw new RuntimeException(e);
}
}

@Override
public void update(Article article) {
String sql = "update article_tbl " +
"set title = ?, content = ?, image_url = ?, like_count = ? " +
"where id = ?";

try (
Connection con = DriverManager.getConnection(JDBC_URL, USER, PASSWORD);
PreparedStatement pstmt = con.prepareStatement(sql);
) {
pstmt.setString(1, article.getTitle());
pstmt.setString(2, article.getContent());
pstmt.setString(3, article.getImageUrl());
pstmt.setLong(4, article.getLikeCount());
pstmt.setLong(5, article.getId());

int updatedRows = pstmt.executeUpdate();
if (updatedRows == 0) {
throw new SQLException("업데이트 실패 - 존재하지 않는 article id=" + article.getId());
}
} catch (SQLException e) {
logger.error("Article 업데이트 실패 id={}", article.getId(), e);
throw new RuntimeException(e);
}
}

@Override
public Optional<Article> findLatest() {
String sql = "select id, creatorId, title, content, image_url, like_count " +
"from article_tbl order by id desc limit 1";

try (
Connection con = DriverManager.getConnection(JDBC_URL, USER, PASSWORD);
PreparedStatement pstmt = con.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
) {
if (!rs.next()) {
return Optional.empty();
}

Article article = new Article(
rs.getLong("id"),
rs.getLong("creatorId"),
rs.getString("title"),
rs.getString("content"),
rs.getString("image_url"),
rs.getLong("like_count")
);

return Optional.of(article);
} catch (SQLException e) {
logger.error("최신 Article 조회 실패", e);
throw new RuntimeException(e);
}
}

@Override
public Optional<Article> findNext(Long id) {
String sql = "select id, creatorId, title, content, image_url, like_count " +
"from article_tbl where id > ? order by id asc limit 1";

try (
Connection con = DriverManager.getConnection(JDBC_URL, USER, PASSWORD);
PreparedStatement pstmt = con.prepareStatement(sql);
) {
pstmt.setLong(1, id);

try (ResultSet rs = pstmt.executeQuery()) {
if (!rs.next()) {
return Optional.empty();
}

Article article = new Article(
rs.getLong("id"),
rs.getLong("creatorId"),
rs.getString("title"),
rs.getString("content"),
rs.getString("image_url"),
rs.getLong("like_count")
);

return Optional.of(article);
}
} catch (SQLException e) {
logger.error("다음 Article 조회 실패 id={}", id, e);
throw new RuntimeException(e);
}
}

@Override
public Optional<Article> findPrev(Long id) {
String sql = "select id, creatorId, title, content, image_url, like_count " +
"from article_tbl where id < ? order by id desc limit 1";

try (
Connection con = DriverManager.getConnection(JDBC_URL, USER, PASSWORD);
PreparedStatement pstmt = con.prepareStatement(sql);
) {
pstmt.setLong(1, id);

try (ResultSet rs = pstmt.executeQuery()) {
if (!rs.next()) {
return Optional.empty();
}

Article article = new Article(
rs.getLong("id"),
rs.getLong("creatorId"),
rs.getString("title"),
rs.getString("content"),
rs.getString("image_url"),
rs.getLong("like_count")
);

return Optional.of(article);
}
} catch (SQLException e) {
logger.error("이전 Article 조회 실패 id={}", id, e);
throw new RuntimeException(e);
}
}
}
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);
}
}

}
24 changes: 21 additions & 3 deletions src/main/java/model/Article.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,31 @@ public class Article {
private String writerName;
private String title;
private String content;
private String imageUrl;
private Long likeCount;

public Article(Long id, Long creatorId, String title, String content) {
public Article(Long id, Long creatorId, String title, String content, String imageUrl, Long likeCount) {
this.id = id;
this.creatorId = creatorId;
this.title = title;
this.content = content;
this.imageUrl = imageUrl;
this.likeCount = likeCount;
}

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;
this.likeCount = 0L;
}

public Long getId() {
return id;
}

public long getCreatorId() {
public Long getCreatorId() {
return creatorId;
}

Expand All @@ -40,11 +46,23 @@ public String getContent() {
return content;
}

public String getImageUrl() {
return imageUrl;
}

public Long getLikeCount() {
return likeCount;
}

public void setId(Long id) {
this.id = id;
}

public void setWriterName(String creatorName) {
this.writerName = creatorName;
}

public void increaseLikeCount() {
likeCount++;
}
}
Loading