React 게시판 첨부파일 등록

Crow·2022년 8월 26일
0

React 게시판

목록 보기
3/3

삽질을 끝내며

import React, {useState} from 'react';
import axios from "axios";
import {useNavigate} from "react-router-dom";


const Register = () => {
    const navigate = useNavigate();
    const [formValue, setFormValue] = useState({
        title: '',
        content: '',
        author: '',
    });

    const [files, setFiles] = useState([]);


    const handleSubmit = async (e) => {
        e.preventDefault()
        const registerFormData = new FormData();

        registerFormData.append("title", formValue.title)
        registerFormData.append("content", formValue.content)
        registerFormData.append("author", formValue.author)
        for (let i = 0; i < files.length; i++) {
            registerFormData.append("files", files[i])
            console.log("안녕" + files[i])
        }



        try {
            const response = await axios({
                method: "post",
                url: "/api/register",
                data: registerFormData,
                headers: {"Content-Type": "multipart/form-data"},
            });
            navigate("/list");
        } catch (error) {
            console.log(error);
        }

    }

    /** data 할당 */
    const handleChange = (event) => {
        setFormValue({
            ...formValue,
            [event.target.name]: event.target.value
        });
    }


    const onChangeFiles = e => {
        setFiles([files, ...e.target.files]);
        console.log(files);
        console.log(files.length + "길이");

 /*       setFiles(f => ([...f, e.target.files[0]]));*/
    }


    return (
        <div>
            <form method={"post"}>
                <h1>글쓰기</h1>
                <p>제목<input name={"title"} value={formValue.title} onChange={handleChange}/></p>
                <p>내용<input name={"content"} value={formValue.content} onChange={handleChange}/></p>
                <p>작성자<input name={"author"} value={formValue.author} onChange={handleChange}/></p>
                <input type={"file"} name={"files"} onChange={onChangeFiles} multiple/>
                <button type={"button"} onClick={handleSubmit}>등록</button>
            </form>


        </div>
    )
}

export default Register;

해당방식 사용시 파일이 여러개 서버로 전송되긴함
그렇지만 몇가지 문제가 있음

첫번째로 일단 속도가 너어어어어어어무 느림 파일 5개랑 꼴랑 게시글 몇개 전송하는대 길게는 10초까지 걸림

그 이유를 좀 찾아봤는대 맞는 내용이 아닐수도 있지만

------WebKitFormBoundaryHNAtInR0RlEvtdaG
Content-Disposition: form-data; name="title"

정리전마지막
------WebKitFormBoundaryHNAtInR0RlEvtdaG
Content-Disposition: form-data; name="content"

정리전마지막
------WebKitFormBoundaryHNAtInR0RlEvtdaG
Content-Disposition: form-data; name="author"

정리전마지막
------WebKitFormBoundaryHNAtInR0RlEvtdaG
Content-Disposition: form-data; name="files"


------WebKitFormBoundaryHNAtInR0RlEvtdaG
Content-Disposition: form-data; name="files"; filename="five.jpg"
Content-Type: image/jpeg


------WebKitFormBoundaryHNAtInR0RlEvtdaG
Content-Disposition: form-data; name="files"; filename="four.jpg"
Content-Type: image/jpeg


------WebKitFormBoundaryHNAtInR0RlEvtdaG
Content-Disposition: form-data; name="files"; filename="one.jpg"
Content-Type: image/jpeg


------WebKitFormBoundaryHNAtInR0RlEvtdaG
Content-Disposition: form-data; name="files"; filename="three.png"
Content-Type: image/png


------WebKitFormBoundaryHNAtInR0RlEvtdaG
Content-Disposition: form-data; name="files"; filename="two.jpg"
Content-Type: image/jpeg


------WebKitFormBoundaryHNAtInR0RlEvtdaG--

일단 요청 페이로드를 보자면 이런 형식임

여기서 중요한게 내 백엔드쪽을 보면

Controller

package com.github.studym.studymarathon.controller;

import com.github.studym.studymarathon.domain.board.dto.BoardDTO;
import com.github.studym.studymarathon.domain.board.dto.MultipartFileDTO;
import com.github.studym.studymarathon.domain.board.dto.PageRequestDTO;
import com.github.studym.studymarathon.domain.board.dto.PageResultDTO;
import com.github.studym.studymarathon.domain.board.entity.Board;
import com.github.studym.studymarathon.domain.board.service.BoardService;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import net.coobird.thumbnailator.Thumbnailator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;

@RestController
@RequestMapping("/api")
@Log4j2
@RequiredArgsConstructor
public class BoardController {

    private final BoardService service;

    @Value("${com.github.studym.studymarathon.path}")
    private String uploadPath;

    @GetMapping("/list")
    public PageResultDTO<BoardDTO, Board> list() {

        PageRequestDTO pageRequestDTO = new PageRequestDTO();

        log.info("list.........." + pageRequestDTO);

        return service.getList(pageRequestDTO);

    }

    @PostMapping(value = "/register", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
    public void register(BoardDTO dto, MultipartFileDTO fileDTO) {
        service.register(dto);

        log.info("/BoardController/register");
        log.info("boardDTO: " + dto);
        log.info("fileDTO: " + fileDTO);

        if (fileDTO != null) {
            fileDTO.getFiles().forEach(multipartFile -> {
                String originalFilename = multipartFile.getOriginalFilename();
                log.info(originalFilename);
                String uuid = UUID.randomUUID().toString();
                Path savePath = Paths.get(uploadPath, uuid + "_" + originalFilename);


                try {
                    multipartFile.transferTo(savePath);

                    if (Files.probeContentType(savePath).startsWith("image")) {
                        File thumbFile = new File(uploadPath, "s_" + uuid + "_" + originalFilename);

                        Thumbnailator.createThumbnail(savePath.toFile(), thumbFile, 200, 200);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }
    }

}

DTO(Board, MultipartFile)

package com.github.studym.studymarathon.domain.board.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class BoardDTO {

    private Long bno;

    private String author;

    private String title;

    private String content;

    private LocalDateTime regDate, modDate;
}
package com.github.studym.studymarathon.domain.board.dto;

import lombok.Data;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

@Data
public class MultipartFileDTO {

    private List<MultipartFile> files;
}

이렇게 됨 files를 List형태로 받기때문에 페이로드에서
------WebKitFormBoundaryHNAtInR0RlEvtdaG
Content-Disposition: form-data; name="files"; filename="five.jpg"
Content-Type: image/jpeg

------WebKitFormBoundaryHNAtInR0RlEvtdaG
Content-Disposition: form-data; name="files"; filename="four.jpg"
Content-Type: image/jpeg
이런방식이 아닌 배열로 받아야 할꺼 같음

이 느린 처리 속도는 내가 보기엔 계속 새로운 배열을 받아서 새로운 DTO에 저장하기 때문으로 보임


멀티파트 구성하다가 file을 String형으로 받을경우도 있었는대 꼭 List로 받아야함
던져 주는쪽에선 배열로 던지는대 받는쪽에서 잘못받는 케이스임

profile
어제보다 개발 더 잘하기 / 많이 듣고 핵심만 정리해서 말하기 / 도망가지 말기 / 깃허브 위키 내용 가져오기

0개의 댓글