project/personal project

[CRUD] 기능구현 - 단일 파일첨부 업로드 및 다운로드

박허디 2024. 1. 10. 17:45

 

관련 화면

 

관련 코드

 

1. application.properties

 

#############################################
#파일 업로드 설정
#############################################
spring.servlet.multipart.location=img/
spring.servlet.multipart.enabled=true
spring.servlet.multipart.max-file-size=10MB

 

파일 업로드를 위한 multipart 설정 추가

 

2. HTML 

 

<input type="file" class="regist_file" id="fileupload">

 

HTML에 파일 업로드 위한 <input> 태그 작성

아이디 작성

 

3.  파일 정보를 저장할 VO 작성

 

package kr.co.crud.domain;

import lombok.Data;

@Data
public class FileVO {

    private int fno;				// 파일번호
    private String parent;			// 게시글 번호
    private String newName;			// 새 파일명
    private String oriName;			// 기존 파일명
    private String del_yn;			// 삭제 여부
    
    private String no; //게시글 번호
}

 

4. JS / Ajax로 파일 전송하기
let btnSave = document.getElementById('btnSave')  // 글 저장 버튼


document.addEventListener('DOMContentLoaded', function() {
    appendEditorHtml();
    addEventListnerCRUDBtn();
});

function addEventListnerCRUDBtn(){
    btnSave.addEventListener('click', fnSave);
}


function fnSave() {

    let fileUpload = document.getElementById("fileupload");   // 파일 업로드
    let formData = new FormData();                            // 파일 업로드를 위한 폼 생성
    let selectedFile = fileUpload.files[0];                   // 업로드한 파일



    let jsonData = {
            "name":selectedFile.name
    };


    if(confirm("등록 하시겠습니까?")) {
        /* 게시글 등록 */
        ajaxAPI("/board/write", jsonData, "POST").then(response => {


            let no = response.no;

             formData.append("file", selectedFile);    // 폼에 파일 추가
             formData.append("oriName", selectedFile.name);

           
                $.ajax({
                    url: '/board/upload',
                    processData: false,
                    contentType: false,
                    data: formData,
                    type: 'POST',
                    beforeSend: function (xhr) {
                        xhr.setRequestHeader(header, token);
                    },
                    success: function (result) {
                        alert("등록 되었습니다.");
                    }
                })


    }


}

 

5. Controller 서버에 업로드

 

controller에서 파일 업로드할 경로(서버)를 설정하고 경로에 업로드

    /* File Upload */
    @PostMapping("/board/upload")
    public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {
        String uploadPath = "파일 업로드 경로";
        String originalFilename = file.getOriginalFilename();  //파일 기존 이름


		//파일 업로드 경로에 파일 업로드 
        Path filePath = Paths.get(uploadPath, originalFilename);
        try {
            Files.write(filePath, file.getBytes());
            return ResponseEntity.ok("File uploaded successfully!");
        } catch (IOException e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body("Failed to upload file. Please try again.");
        }
    }

 

6. Service 파일 정보를 DB에 저장

 

Service에서 파일명 새로 수정 후 해당 파일의 정보를 DB에 저장

 

  public void updateFile(BoardVO boardVO){

        /* 불러진 원래 파일명 가져오기 */
        String oriName = boardVO.getName();
        /* .확장자명 앞에까지 자르기 */
        String tempName = oriName.substring(oriName.lastIndexOf("."));
        /* 랜덤명생성 */
        String newName = UUID.randomUUID().toString() + tempName;

        /* 파일 정보 작성 */
        FileVO fileVO = new FileVO();
        fileVO.setParent(todayDateString);
        fileVO.setOriName(oriName);
        fileVO.setNewName(newName);

        boardDAO.updateFile(fileVO);
        
    }
7. DAO 
 /* 파일 올리기 */
    public void updateFile(BoardVO boardVO);
8. xml / DB 저장
    <insert id="insertFile" parameterType="kr.co.crud.domain.FileVO">
        INSERT INTO
            CRUD_FILE
        SET
            PARENT = #{parent},
            NEWNAME = #{newName},
            ORINAME = #{oriName}
    </insert>
9. 파일 다운로드

 

업로드한 파일을 클릭 시 파일 다운로드

<div class="content_middle_bottom" id="fileDown" th:text="${board.oriname}" th:data-fno="${board.fno}"></div>

 

위 페이지와 연결된 JS에서 클릭시 다운로드할 수 있도록 만들기

let btnFileDownload = document.getElementById('fileDown')  // 파일 다운로드

document.addEventListener('DOMContentLoaded', function() {
    addEventListenerCRUDBtn();
});

document.addEventListener('DOMContentLoaded', function() {
    addEventListenerCRUDBtn();
});


/* 파일 다운로드 */
function fnFileDownLoad() {

    let fileNo = btnFileDownload.getAttribute("data-fno");

    ajaxAPI("/board/fileDownload?fno=" + fileNo, null, "GET").then(response => {
    window.location.href = '/board/fileDownload?fno=' + fileNo;
    })

}

 

그 후 파일 첨부할때와 비슷하게 controller - service 연결

 

10. 파일 다운로드 controller 
    /* 파일 다운로드 */
    @GetMapping("/board/fileDownload")
    @ResponseBody
    public ResponseEntity<Resource> fileDownload(@RequestParam("fno") String fno) throws IOException {

        int fnoInt = Integer.parseInt(fno);

        FileVO file = boardService.selectFile(fnoInt);

        ResponseEntity<Resource> response = boardService.fileDownload(file.getOriName());

        return response;

    }
11. 파일 다운로드 service
    /* 첨부파일 다운로드 */
    public ResponseEntity<Resource> fileDownload(String oriName) throws IOException {

        String uploadPath = "/Users/parkjehyeong/Desktop/upload/";
        Path path = Paths.get(uploadPath, oriName);

        String contentType = Files.probeContentType(path);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentDisposition(ContentDisposition.builder("attachment")
                .filename(oriName)
                .build());

        headers.add(HttpHeaders.CONTENT_TYPE, contentType);
        Resource resource = new InputStreamResource(Files.newInputStream(path));

        return new ResponseEntity<>(resource, headers, HttpStatus.OK);

    }