스프링 부트/[스프링 부트] 게시판 무작정 따라하기

[스프링 부트] 게시판 무작정 따라하기 - 7. 파일 업로드

sungw00 2023. 3. 13. 12:35
728x90

파일을 저장할 수 있도록 DB에 컬럼 추가

filename과 filepath 컬럼을 추가한 후 apply

 

게시글을 작성할 때 파일을 첨부할 수 있도록 작성

boardwrite.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>게시물 작성폼</title>
</head>

<style>
    .layout {
        width: 500px;
        margin: 0 auto;
        margin-top: 40px;
    }

    .layout input {
        width: 100%;
        box-sizing: border-box;
    }

    .layout textarea {
        width: 100%;
        margin-top: 10px;
        min-height: 300px;
    }
</style>

<body>
    <div class="layout">
        <form action="/board/writepro" method="post" encType="multipart/form-data">
            <input name="title" type="text">
            <textarea name="content"></textarea>
            <input type="file" name="file">
            <button type="submit">작성</button>
        </form>
    </div>
</body>
</html>

글 확인 시 버튼을 클릭하면 이미지를 확인할 수 있는 코드 작성

boardview.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>게시글 상세 페이지</title>
</head>
<body>

<h1 th:text="${board.title}">제목입니다.</h1>
<p th:text="${board.content}">내용이 들어갈 부분입니다.</p>
<a th:href="@{${board.filepath}}">이미지 확인하기</a>
<a th:href="@{/board/delete(id=${board.id})}">글 삭제</a>
<a th:href="@{/board/modify/{id}(id = ${board.id})}">수정</a>
</body>
</html>

Board 엔티티에 filename과 filepath 추가

package com.study2.board.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Data;

@Entity
@Data
public class Board {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String title;
    private String content;
    private String filename; // 파일 이름
    private String filepath; // 파일이 저장된 경로
}

html 파일에서 입력받는 name과 컨트롤러에 file이라는 매개변수 이름을 일치시켜주어야 함

 

BoardService

package com.study2.board.service;

import com.study2.board.entity.Board;
import com.study2.board.repository.BoardRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.List;
import java.util.UUID;

@Service
public class BoardService {

    @Autowired
    private BoardRepository boardRepository;

    // 글 작성 처리
    public void write(Board board, MultipartFile file) throws Exception {

        // 파일 업로드 처리 시작
        String projectPath = System.getProperty("user.dir") // 프로젝트 경로를 가져옴
                + "\\src\\main\\resources\\static\\files"; // 파일이 저장될 폴더의 경로

        UUID uuid = UUID.randomUUID(); // 랜덤으로 식별자를 생성

        String fileName = uuid + "_" + file.getOriginalFilename(); // UUID와 파일이름을 포함된 파일 이름으로 저장

        File saveFile = new File(projectPath, fileName); // projectPath는 위에서 작성한 경로, name은 전달받을 이름

        file.transferTo(saveFile);

        board.setFilename(fileName);
        board.setFilepath("/files/" + fileName); // static 아래부분의 파일 경로로만으로도 접근이 가능
        // 파일 업로드 처리 끝

        boardRepository.save(board); // board를 저장소에 save
    }

    // 게시글 리스트 처리
    public List<Board> boardList() {
        return boardRepository.findAll();
    }

    // 특정 게시글 불러오기
    public Board boardView(Integer id) {
        return boardRepository.findById(id).get();
    }

    // 특정 게시글 삭제
    public void boardDelete(Integer id) {
        boardRepository.deleteById(id);
    }
}

 

컨트롤러의 boardWritePro 메서드에 내용 추가

@PostMapping("/board/writepro")
    public String boardWritePro(Board board, Model model, MultipartFile file) throws Exception { // 데이터가 board에 담겨서 들어옴

        boardService.write(board, file);

        model.addAttribute("message", "글 작성이 완료되었습니다.");
        model.addAttribute("searchUrl", "/board/list");

        return "message";
    }

 

프로젝트 실행 후 localhost:8080/board/write에서 내용을 작성 후 이미지 확인하기 버튼 클릭하여 내용확인하기

주소창에 이미지가 저장된 경로와 UUID를 포함한 이미지 파일의 이름을 출력

DB에도 이미지 파일의 이름과 이미지 파일의 경로가 잘 저장된 것을 확인할 수 있다.


그런데... 이렇게 하면 파일을 업로드한 후 바로 이미지를 보려고하면 404 에러가 뜨면서 파일을 찾을 수 없다고 뜬다.

이러한 오류를 해결하는 방법을 코드에 반영해보자.

먼저, 프로젝트 폴더/src/main/ 하위에 webapp 폴더를 아래와 같이 생성해준다.(이곳에 이미지를 저장하도록 할 것이다.)

그리고 src/main/resources/application.properties에 다음 내용을 추가해준다.

spring.mvc.static-path-pattern=/webapp/**

static 경로를 webapp 하위에 있는 파일 중 찾는다고 변경하는 코드이다.

 

이후에 서비스에서 경로에 대한 두 가지 부분을 수정

public void write(Board board, MultipartFile file) throws Exception {

        String projectPath = System.getProperty("user.dir")
                + "\\src\\main\\webapp\\"; // 이렇게 수정해주고,

        UUID uuid = UUID.randomUUID(); 

        String fileName = uuid + "_" + file.getOriginalFilename(); 

        File saveFile = new File(projectPath, fileName); 

        file.transferTo(saveFile);

        board.setFilename(fileName);
        board.setFilepath("/webapp/" + fileName); // 이렇게 수정해주면 완료

        boardRepository.save(board);
    }

이후에 다시 파일업로드를 하고 바로 이미지를 확인하면 정상적으로 이미지가 출력되는 것을 볼 수 있다.

업로드 후 이미지 확인하기 클릭
이미지 정상 출력

728x90