본문 바로가기

👩‍💻 BackEnd/🌿 스프링 [Spring]

[ Spring / fileUpload ] File Upload / File Download 기능 구현

개발 환경 

  • sts 4 
  • mybatis 
  • oracle xe 11g

요구사항

  • 파일 업로드 
    • 각 게시글 업로드 시 파일 첨부
    • 파일 저장 시 게시글 별로 폴더 새로 생성해서 저장
    • uuid + 업로드 파일 이름 형식으로 파일 저장  
  • 파일 다운로드 
    • 다운로드 받을 때는 uuid가 없는 원본 파일 이름으로 다운로드 

 

파일 업로드 

// 컨트롤러 
@PostMapping("/board/write")
public String insertBoard(BoardListDto dto, Model model, HttpSession session) throws Exception {

    Long userId = (Long) session.getAttribute(SessionConst.USER_ID);

    if (userId == null) {
        throw new CustomException(-1, "로그인 정보가 없습니다.");
    }

    dto.setUserId(userId);
    boardServiceImpl.insertBoard(dto);
    return "redirect:/";
}

 

// 서비스 
@Override
public int insertBoard(BoardListDto dto) throws Exception {
    log.info("serviceImpl dto = {}", dto);

    BoardListDto board = BoardListDto.builder()
            .title(dto.getTitle())
            .content(dto.getContent())
            .files(dto.getFiles())
            .commentCnt(dto.getCommentCnt())
            .userId(dto.getUserId()) // 로그인한 // 이름 저장
            .build();

    // board 정보를 db 에 insert 
    int result = boardMapper.insertBoard(board);


	// 파일 업로드 처리 : 각 게시글 마다 다른 폴더에 저장하기 위해 폴더를 생성하는 메서드 작성 후 활용
    String boardFolderPath = createFolder(path, board.getBoardId());

    File file = new File(boardFolderPath);

    // 경로가 없을 경우 파일을 생성
    if (!file.exists()) {
        file.mkdirs();
    }

    for (MultipartFile f : board.getFiles()) {

        if (!f.isEmpty()) {

            log.info("file => {}", f.getOriginalFilename());

            // HDD SAVE
            String fileName = fileManager.saveFile(f, boardFolderPath);

            // DB SAVE
            UploadFileVO uploadFileVO = UploadFileVO.builder()
                    .orgFileName(f.getOriginalFilename())
                    .saveFileName(fileName)
                    .savePath(boardFolderPath)
                    .fileSize(f.getSize())
                    .boardId(board.getBoardId())
                    .build();

            // file 정보를 db 에 insert
            boardMapper.insertFile(uploadFileVO);
        }
    }
    return result;
}

 

private String createFolder(String basePath, Long boardId) {
    String folderPath = basePath + "/" + boardId;
    File folder = new File(folderPath);
    if (!folder.exists()) {
        folder.mkdirs();
    }
    return folderPath;
}

 

Mapper

@Mapper
public interface BoardMapper {
    // 첨부파일 업로드
    public int insertFile(UploadFileVO fileVO) throws Exception;
    
}

 

mapper.xml

<!-- 첨부파일 업로드 -->
<insert id="insertFile" parameterType="fileVO">
        INSERT INTO UPLOADFILE(
            UPLOADFILE_ID,
            BOARD_ID,
            ORG_FILE_NAME,
            SAVE_FILE_NAME,
            SAVE_PATH,
            FILE_SIZE
        ) VALUES(
            UPLOADFILE_SEQ.nextval,
            #{boardId},
            #{orgFileName},
            #{saveFileName},
            #{savePath},
            #{fileSize}
        )
</insert>

 


파일 다운로드 

// 파일 다운로드 처리
@GetMapping("/fileDownload/{boardId}/{saveFileName}/{orgFileName}")
public void fileDownload(@PathVariable String boardId, @PathVariable String saveFileName, @PathVariable String orgFileName, HttpServletResponse response)
        throws IOException {

    // 게시글 별로 폴더를 생성하여 파일을 따로 저장해줬으므로 @PathVariable 로 받아온 게시글의 id(폴더 이름), 저장된 파일 이름을 더해서 저장 경로를 수정한다. 
    String folderPath = path + "/" + boardId;

    // 저장 경로와 불러올 파일의 이름을 파라미터로 넘겨 파일을 찾아온다. 
    File f = new File(folderPath, saveFileName);

    log.info("folderPath = {}", folderPath);

    // file 다운로드 설정
    response.setContentType("application/download");
    response.setContentLength((int) f.length());
	
    // encoding 을 해줘야 파일 경로를 제대로 잘 찾아감.
    String fileName = URLEncoder.encode(orgFileName, "UTF-8");

    response.setHeader("Content-disposition", String.format("attachment; filename=\"%s\";", fileName) + "\"");
    // response 객체를 통해서 서버로부터 파일 다운로드
    OutputStream os = response.getOutputStream();
    // 파일 입력 객체 생성
    FileInputStream fis = new FileInputStream(f);
    FileCopyUtils.copy(fis, os);
    fis.close();
    os.close();
}