이 글은 Velog에서 이전한 글입니다. Velog 원문 보기
지난 💡게시판 - 파일 업로드에서 게시판의 여러가지 부족한 점을 이야기 했다.
- *수정 페이지에서 사진 수정이 불가하다. *
- 파일 다운로드 기능이 없다.
- 사진을 보기 위해서는 서버 재실행이 필요하다.
- 사진을 클릭해서 보는 것이 아닌 게시글 상세 페이지에 보이고 싶다.
등등이 있는데 오늘은 그 중 수정 페이지에서 사진 수정이 불가하다는 사항을 개선해보려고 한다.
Board
package com.studyweb.webboard.entity;
import lombok.Builder;
import lombok.Data;
import javax.persistence.*;
@Entity
@Data
public class Board extends TimeEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String title;
private String content;
private String author;
private String filename;
private String filepath;
//수정을 위한 생성자
@Builder
public Board(String title, String content, String author) {
this.title = title;
this.content = content;
this.author = author;
}
public void update(String title, String content) {
this.title = title;
this.content = content;
}
//기본 생성자 추가!
public Board() {
}
}
Entity 클래스인 Board의 전체 코드이다.
BoardService 전체 로직
package com.studyweb.webboard.service;
import com.studyweb.webboard.entity.Board;
import com.studyweb.webboard.repository.BoardRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.util.List;
import java.util.UUID;
@Service
@RequiredArgsConstructor
public class BoardService {
private final BoardRepository boardRepository;
public Board findById(Integer id) {
return boardRepository.findById(id).get();
}
public Page<Board> boardList(Pageable pageable) {
return boardRepository.findAll(pageable);
}
public Page<Board> boardSearchList(String searchKeyword, Pageable pageable) {
return boardRepository.findByTitleContaining(searchKeyword, pageable);
}
public void save(Board board, MultipartFile file) throws Exception {
//저장할 경로를 지정
String projectPath = getProjectPath();
// 랜덤 식별자 생성
UUID uuid = UUID.randomUUID();
// uuid + _ + 파일의 원래 이름
String fileName = uuid + "_" + file.getOriginalFilename();
//파일을 생성할 것인데 경로는 projectPath, 이름은 filename로 담긴다는 뜻
File saveFile = new File(projectPath, fileName);
file.transferTo(saveFile);
board.setFilename(fileName); //DB에 filename 저장
board.setFilepath("/files/" + fileName);
boardRepository.save(board);
}
public void delete(Integer id) {
boardRepository.deleteById(id);
}
public void update(Integer id, Board updateBoard, MultipartFile file) throws Exception {
Board board = boardRepository.findById(id).get();
board.update(updateBoard.getTitle(), updateBoard.getContent());
boardRepository.save(board);
private static String getProjectPath() {
return System.getProperty("user.dir") + "/src/main/resources/static/files";
}
}
우선 위는 게시판의 기능들을 모아둔 BoardService의 전체 로직이다. 이번에는 update 메서드를 수정해볼 것이다.
우선 save 메서드에 있는 것처럼 update 메서드 또한 파일을 매개변수로 받고 filename, filepath 지정해주는 코드가 필요하다. 이는 save에 있는 코드를 그대로 쓰겠다.
public void update(Integer id, Board updateBoard, MultipartFile file) throws Exception {
Board board = boardRepository.findById(id).get();
board.update(updateBoard.getTitle(), updateBoard.getContent());
//저장할 경로를 지정
String projectPath = getProjectPath();
// 랜덤 식별자 생성
UUID uuid = UUID.randomUUID();
// uuid + _ + 파일의 원래 이름
String fileName = uuid + "_" + file.getOriginalFilename();
//파일을 생성할 것인데 경로는 projectPath, 이름은 filename로 담긴다는 뜻
File saveFile = new File(projectPath, fileName);
file.transferTo(saveFile);
board.setFilename(fileName); //DB에 filename 저장
board.setFilepath("/files/" + fileName);
boardRepository.save(board);
private static String getProjectPath() {
return System.getProperty("user.dir") + "/src/main/resources/static/files";
코드를 추가해줬다. 여기서 중요한 부분이 있다.
게시글을 수정할 때는 2가지 상황이 존재한다
- 파일을 수정하는 경우
- 파일을 수정하지 않는 경우
수정을 할 때마다 파일을 수정한다면 괜찮겠지만 아니라면 문제가 생긴다.
현재의 코드는 게시글을 수정할 때 파일을 수정하지 않고 게시글을 수정하게 된다면 이전의 파일이 사라진다는 문제를 가지고 있다.
파일을 수정하는 경우, 파일을 수정하지 않는 경우를 조건문으로 구분하겠다.
public void update(Integer id, Board updateBoard, MultipartFile file) throws Exception {
Board board = boardRepository.findById(id).get();
board.update(updateBoard.getTitle(), updateBoard.getContent());
if (file.isEmpty()) {
boardRepository.save(board);
} else {
//저장할 경로를 지정
String projectPath = getProjectPath();
// 랜덤 식별자 생성
UUID uuid = UUID.randomUUID();
// uuid + _ + 파일의 원래 이름
String fileName = uuid + "_" + file.getOriginalFilename();
//파일을 생성할 것인데 경로는 projectPath, 이름은 filename로 담긴다는 뜻
File saveFile = new File(projectPath, fileName);
file.transferTo(saveFile);
board.setFilename(fileName); //DB에 filename 저장
board.setFilepath("/files/" + fileName);
boardRepository.save(board);
}
}
private static String getProjectPath() {
return System.getProperty("user.dir") + "/src/main/resources/static/files";
}
조건문을 추가해서 file.isEmpty()가 True인 경우 파일을 수정하지 않은 경우로 보고 이전의 파일을 그대로 사용하도록 했다.
이제 html을 수정하자.
boardUpdate.html - 수정 전
<body>
<div class="container">
<h1>게시글 수정</h1>
<form th:action="@{/board/post/update/{id}(id=${post.id})}" method="post">
<div class="form-group">
<label for="title">제목</label>
<input type="text" id="title" name="title" th:value="${post.title}" required>
</div>
<div class="form-group">
<label for="author">작성자</label>
<input type="text" id="author" name="author" th:value="${post.author}" disabled>
</div>
<div class="form-group">
<label for="content">내용</label>
<textarea id="content" name="content" rows="8" required th:text="${post.content}"></textarea>
</div>
<button type="submit" class="btn">수정하기</button>
</form>
</div>
</body>
수정 전의 boardUpdate.html 코드이다. 제목과 내용이 수정하는 input이 있고, 작성자는 disable을 추가해서 수정이 불가하게 작성했다. (
GPT가 해줬다.
)
이제 수정을 해보자.
boardUpdate.html - 수정 후
<body>
<div class="container">
<h1>게시글 수정</h1>
<!--enctype="multipart/form-data" 추가-->
<form th:action="@{/board/post/update/{id}(id=${post.id})}" method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="title">제목</label>
<input type="text" id="title" name="title" th:value="${post.title}" required>
</div>
<div class="form-group">
<label for="author">작성자</label>
<input type="text" id="author" name="author" th:value="${post.author}" disabled>
</div>
<div class="form-group">
<label for="content">내용</label>
<textarea id="content" name="content" rows="8" th:text="${post.content}" required></textarea>
<!--파일 업로드 부분 추가-->
<a th:href="@{${post.filepath}}">사진</a>
<input type="file" name="file">
<!--파일 업로드 부분 끝-->
</div>
<button type="submit" class="btn">수정하기</button>
</form>
</div>
</body>
큰 변화는 없다.
form 태그에 enctype="multipart/form-data"를 추가했다. 단순히 텍스트를 변경할 때는 필요 없지만 파일 수정이 추가되면서 여러 형태의 데이터를 변경함에 따라서 타입을 Multipart/form-data로 해야한다.
<!--게시글 작성 때 등록한 파일을 보는 코드-->
<a th:href="@{${post.filepath}}">사진</a>
<!--수정할 파일을 올리는 코드-->
<input type="file" name="file">
게시글을 작성할 때 등록했던 파일을 보는 코드와 수정할 파일을 업로드 하는 코드를 추가했다.
여기까지하면 디자인은 별로지만 기능의 추가는 끝이났다.
여전히 부족한 점이 많다.
-
*수정 페이지에서 사진 수정이 불가하다. * - 파일 다운로드 기능이 없다.
- 사진을 보기 위해서는 서버 재실행이 필요하다.
- 사진을 클릭해서 보는 것이 아닌 게시글 상세 페이지에 보이고 싶다.
위의 내용과 더불어
- 사진을 클릭해서 보는 것이 아닌 바로 보이게 하고 싶다.
- 업로드한 파일을 삭제하게 만들고 싶다.
- 파일 업로드 디자인 수정
등등 파일 업로드 부분을 제외하고 다른 부분에서도 수정해야 할 부분이 많다.
기능을 추가하고, 수정하면서 부족함 점이 끝도 없이 보이다 보니 계속해서 배워나가는 시간인 것 같다. 언젠가 다른 사람들에게 자랑스럽게 보여주고 배포할 수 있는 프로젝트를 만들 때까지 열심히 달려나가야겠다!
글에서 부족한 부분이 많을 것 같습니다. 모든 지적을 환영합니다!!
더 자세한 코드는 깃허브를 참고해주세요!
'Project > 나의 작은 프로젝트' 카테고리의 다른 글
| 💡 게시판 - 파일 다운로드 (1) | 2026.07.20 |
|---|---|
| 💡 게시판 - 파일 업로드 3(개선) (0) | 2026.07.20 |
| 💡 게시판 - 파일 업로드 (0) | 2026.07.20 |
| 💡 게시판 - 검색 기능 (0) | 2026.07.20 |
| 💡 게시판 - 페이징 처리 (0) | 2026.07.20 |