์ง๋ ๐ก๊ฒ์ํ - ํ์ผ ์ ๋ก๋์์ ๊ฒ์ํ์ ์ฌ๋ฌ๊ฐ์ง ๋ถ์กฑํ ์ ์ ์ด์ผ๊ธฐ ํ๋ค.
์์ ํ์ด์ง์์ ์ฌ์ง ์์ ์ด ๋ถ๊ฐํ๋ค.
ํ์ผ ๋ค์ด๋ก๋ ๊ธฐ๋ฅ์ด ์๋ค.
์ฌ์ง์ ๋ณด๊ธฐ ์ํด์๋ ์๋ฒ ์ฌ์คํ์ด ํ์ํ๋ค.
์ฌ์ง์ ํด๋ฆญํด์ ๋ณด๋ ๊ฒ์ด ์๋ ๊ฒ์๊ธ ์์ธ ํ์ด์ง์ ๋ณด์ด๊ณ ์ถ๋ค.
๋ฑ๋ฑ์ด ์๋๋ฐ ์ค๋์ ๊ทธ ์ค ์์ ํ์ด์ง์์ ์ฌ์ง ์์ ์ด ๋ถ๊ฐํ๋ค
๋ ์ฌํญ์ ๊ฐ์ ํด๋ณด๋ ค๊ณ ํ๋ค.
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">
๊ฒ์๊ธ์ ์์ฑํ ๋ ๋ฑ๋กํ๋ ํ์ผ์ ๋ณด๋ ์ฝ๋์ ์์ ํ ํ์ผ์ ์ ๋ก๋ ํ๋ ์ฝ๋๋ฅผ ์ถ๊ฐํ๋ค.
์ฌ๊ธฐ๊น์งํ๋ฉด ๋์์ธ์ ๋ณ๋ก์ง๋ง ๊ธฐ๋ฅ์ ์ถ๊ฐ๋ ๋์ด๋ฌ๋ค.
์ฌ์ ํ ๋ถ์กฑํ ์ ์ด ๋ง๋ค.
์์ ํ์ด์ง์์ ์ฌ์ง ์์ ์ด ๋ถ๊ฐํ๋ค.
ํ์ผ ๋ค์ด๋ก๋ ๊ธฐ๋ฅ์ด ์๋ค.
์ฌ์ง์ ๋ณด๊ธฐ ์ํด์๋ ์๋ฒ ์ฌ์คํ์ด ํ์ํ๋ค.
์ฌ์ง์ ํด๋ฆญํด์ ๋ณด๋ ๊ฒ์ด ์๋ ๊ฒ์๊ธ ์์ธ ํ์ด์ง์ ๋ณด์ด๊ณ ์ถ๋ค.
์์ ๋ด์ฉ๊ณผ ๋๋ถ์ด
์ฌ์ง์ ํด๋ฆญํด์ ๋ณด๋ ๊ฒ์ด ์๋ ๋ฐ๋ก ๋ณด์ด๊ฒ ํ๊ณ ์ถ๋ค.
์ ๋ก๋ํ ํ์ผ์ ์ญ์ ํ๊ฒ ๋ง๋ค๊ณ ์ถ๋ค.
ํ์ผ ์ ๋ก๋ ๋์์ธ ์์
๋ฑ๋ฑ ํ์ผ ์ ๋ก๋ ๋ถ๋ถ์ ์ ์ธํ๊ณ ๋ค๋ฅธ ๋ถ๋ถ์์๋ ์์ ํด์ผ ํ ๋ถ๋ถ์ด ๋ง๋ค.
๊ธฐ๋ฅ์ ์ถ๊ฐํ๊ณ , ์์ ํ๋ฉด์ ๋ถ์กฑํจ ์ ์ด ๋๋ ์์ด ๋ณด์ด๋ค ๋ณด๋ ๊ณ์ํด์ ๋ฐฐ์๋๊ฐ๋ ์๊ฐ์ธ ๊ฒ ๊ฐ๋ค. ์ธ์ ๊ฐ ๋ค๋ฅธ ์ฌ๋๋ค์๊ฒ ์๋์ค๋ฝ๊ฒ ๋ณด์ฌ์ฃผ๊ณ ๋ฐฐํฌํ ์ ์๋ ํ๋ก์ ํธ๋ฅผ ๋ง๋ค ๋๊น์ง ์ด์ฌํ ๋ฌ๋ ค๋๊ฐ์ผ๊ฒ ๋ค!
๊ธ์์ ๋ถ์กฑํ ๋ถ๋ถ์ด ๋ง์ ๊ฒ ๊ฐ์ต๋๋ค. ๋ชจ๋ ์ง์ ์ ํ์ํฉ๋๋ค!!
๋ ์์ธํ ์ฝ๋๋ ๊นํ๋ธ๋ฅผ ์ฐธ๊ณ ํด์ฃผ์ธ์!
๊นํ๋ธ: https://github.com/pp8817/ToyProjectBoard