파일 업로드 기능 구현하기

친친·2022년 10월 23일
0

게시판에 파일 업로드 기능을 추가해본다.
파일을 업로드하면 실제 파일은 Spring 내장서버(tomcat)에 저장되고,
DB에는 파일 이름과 파일 경로만 저장된다.
전체 흐름은 다음과 같다.

  • DB에 파일이름과 파일경로를 저장하기 위한 column을 추가한다
  • DB 테이블과 연동된 Board.java에도 변수를 추가한다
  • 글작성 폼에 파일 업로드를 하기 위한 input 태그를 추가한다
  • 첨부한 파일을 저장할 폴더를 만든다
  • boardService.java에서 write()메서드에 파일을 받기위한 매개변수와 관련 코드를 추가한다
  • boardController.java에서 수정된 write()를 이용하는 메서드들을 찾아 변경한다
  • 게시글 상세 페이지(boardview.html)에 첨부한 파일을 볼 수 있는 링크를 추가한다


위 그림처럼 강의에선 workbench라는 비주얼 DB툴을 이용하여
테이블에 filename과 filepath 컬럼을 추가했다.


//board.java

@Entity//DB 테이블과 연동해주는 어노테이션
@Data //변수에 getter, setter 자동생성
public class Board {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String title;
    private String content;

    private String filename;
    private String filepath;
}

테이블과 연동된 board에도 똑같은 변수명으로 파일이름과 파일경로를 추가해준다.


//boardwrite.html
...
<body>
    <div class="layout">  <!--enctype="multipart/form-data" 파일이나 이미지를 서버로 전송할 때 주로 사용-->
        <form action="/board/writepro" method="post" enctype="multipart/form-data">
            <input name="title" type="text" placeholder="제목">
            <textarea name="content" placeholder="본문입력"></textarea>
          
            <input type="file" name="file">
          
            <button type="submit">작성</button>
        </form>
    </div>
</body>

글작성 폼에서 파일 업로드를 위한 input 태그를 추가해준다
form 태그의 enctype="multipart/form-data"은 주로 이미지나 파일을 서버로 업로드할 때 주로 사용하는 속성이다
enctype 3가지 속성 더 알아보기



한코딩 강의에서는 업로드 파일을 저장하기 위한 폴더를 /main/resources/static/files에 만들었다. 하지만 이 경우, 파일을 업로드하고 서버를 재기동해야 이미지가 보이는 문제가 생겨서 다음과 같이 수정하였다. 위 그림과 같이 main폴더 밑에 webapp이란 폴더를 만들어 주고, template 폴더 아래 있는 application.properties에 아래 코드를 한 줄 추가한다.

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

static 경로를 webapp 밑으로 된 파일들에서 찾는다고 변경한다는 코드이다


//boardService.java
...
    public void write(Board board, MultipartFile file) throws Exception{
        
        //System.getProperty("user.dir") : 현재 프로젝트 경로를 가져옴
        String projectPath = System.getProperty("user.dir") + "\\src\\main\\webapp";

        UUID uuid = UUID.randomUUID();//랜덤이름생성
        String fileName = uuid + "_" + file.getOriginalFilename();

        //파일을 담을 껍데기를 만들어 파일경로와 파일이름을 매개변수로 넣고
        File saveFile = new File(projectPath, fileName);
        //throws Exception으로 예외처리
        //업로드된 파일을 껍데기에 담아 저장해준다
        file.transferTo(saveFile);
        
        //board 객체에 파일이름과 파일경로를 set()하여 DB에 저장한다
        board.setFilename(fileName);
        board.setFilepath("/webapp/" + fileName);
        boardRepository.save(board);
    }

파일경로와 파일이름을 new File()생성자의 매개변수로 담아서 transferTo() 메서드를 이용해 업로드 파일을 저장해준다. 이때, 현재 프로젝트의 경로를 받아오기 위해 ystem.getProperty("user.dir")를 사용하고, 업로드된 파일 이름들의 중복을 방지하기 위해 UUID를 이용해서 파일이름을 만든다. 실제 파일 원본은 스프링에 내장된 톰캣 서버에 저장되고, DB에는 파일이름과 파일경로만 저장한다.
System.getProperty() 더 알아보기
UUID.randomUUID() 더 알아보기


//boardController.java
...
    //글작성
    @PostMapping("/board/writepro")
    public String boardWritePro(Board board, 
    							Model model, 
                                MultipartFile file) throws Exception{
		
        //NPE 오류방지를 위해 메서드에 throws Exception 처리를 해준다
        boardService.write(board, file);
        model.addAttribute("message", "글 작성이 완료되었습니다");
        model.addAttribute("searchUrl", "/board/list");
        return "message";
    }
 ...   
    //글수정
    @PostMapping("/board/update/{id}")
    public String boardUpdate(@PathVariable("id") Integer id, 
    						Board board, Model model, 
                            MultipartFile file) throws Exception{

        Board boardTemp = boardService.boardView(id);
        boardTemp.setTitle(board.getTitle());
        boardTemp.setContent(board.getContent());
        boardService.write(boardTemp, file);

        model.addAttribute("message", "글 수정이 완료되었습니다");
        model.addAttribute("searchUrl", "/board/list");
        return "message";
    }

Service의 write()을 사용한 Controller 부분도 찾아서 위와 같이 수정해준다.
-각 메서드에 매개변수 추가하기
-throws Exception처리하기


//boardview.html
...
<body>
<h1 th:text="${board.title}">제목입니다</h1>
<p th:text="${board.content}">내용이 들어갈 부분입니다</p>

//DB에 저장된 파일경로를 링크로 걸어준다
<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>

게시글 상세페이지에서 첨부한 파일을 다운받을 수 있는 링크를 첨부해준다.



[출처] 위 내용은 한코딩님의 유튜브 강의를 정리한 내용입니다

https://youtu.be/qeB2GzrSFAc

profile
웹개발 블로그

0개의 댓글