삽질을 끝내며
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--
일단 요청 페이로드를 보자면 이런 형식임
여기서 중요한게 내 백엔드쪽을 보면
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();
}
});
}
}
}
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로 받아야함
던져 주는쪽에선 배열로 던지는대 받는쪽에서 잘못받는 케이스임