๐Ÿ’ก ๊ฒŒ์‹œํŒ - ํŒŒ์ผ ์—…๋กœ๋“œ 2

๋ฐ•์ƒ๋ฏผยท2023๋…„ 9์›” 10์ผ
0

๋‚˜์˜ ์ž‘์€ ํ”„๋กœ์ ํŠธ

๋ชฉ๋ก ๋ณด๊ธฐ
6/10
post-thumbnail

์ง€๋‚œ ๐Ÿ’ก๊ฒŒ์‹œํŒ - ํŒŒ์ผ ์—…๋กœ๋“œ์—์„œ ๊ฒŒ์‹œํŒ์˜ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ถ€์กฑํ•œ ์ ์„ ์ด์•ผ๊ธฐ ํ–ˆ๋‹ค.

  • ์ˆ˜์ • ํŽ˜์ด์ง€์—์„œ ์‚ฌ์ง„ ์ˆ˜์ •์ด ๋ถˆ๊ฐ€ํ•˜๋‹ค.

  • ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ๊ธฐ๋Šฅ์ด ์—†๋‹ค.

  • ์‚ฌ์ง„์„ ๋ณด๊ธฐ ์œ„ํ•ด์„œ๋Š” ์„œ๋ฒ„ ์žฌ์‹คํ–‰์ด ํ•„์š”ํ•˜๋‹ค.

  • ์‚ฌ์ง„์„ ํด๋ฆญํ•ด์„œ ๋ณด๋Š” ๊ฒƒ์ด ์•„๋‹Œ ๊ฒŒ์‹œ๊ธ€ ์ƒ์„ธ ํŽ˜์ด์ง€์— ๋ณด์ด๊ณ  ์‹ถ๋‹ค.

๋“ฑ๋“ฑ์ด ์žˆ๋Š”๋ฐ ์˜ค๋Š˜์€ ๊ทธ ์ค‘ ์ˆ˜์ • ํŽ˜์ด์ง€์—์„œ ์‚ฌ์ง„ ์ˆ˜์ •์ด ๋ถˆ๊ฐ€ํ•˜๋‹ค๋Š” ์‚ฌํ•ญ์„ ๊ฐœ์„ ํ•ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค.

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

profile
์Šคํ”„๋ง ๋ฐฑ์—”๋“œ๋ฅผ ๊ณต๋ถ€์ค‘์ธ ๋Œ€ํ•™์ƒ์ž…๋‹ˆ๋‹ค!

0๊ฐœ์˜ ๋Œ“๊ธ€