MultiPartFile์ ์ด์ฉํ ํ์ผ ์ ๋ก๋, ๋ค์ด๋ก๋
by rlaehddnd0422์คํ๋ง์ด ์ ๊ณตํ๋ MultiPartFile์ ์ด์ฉํด ํ์ผ ์ ์ก ๋ฟ๋ง ์๋๋ผ ์ ์กํ ํ์ผ์ ๋ค์ด๋ฐ๋ ์์ ์ค์ต
์๊ตฌ์ฌํญ
- ์ํ(Item)์ ๋ฑ๋กํ๊ณ ์กฐํ
- ์ํ์ ์์๋ก๋ ์ํ ์์ด๋, ์ํ์ด๋ฆ, ์ํ ํ์ผ, ํ์ผ ๋ฆฌ์คํธ๊ฐ ์์ต๋๋ค.
- ์ํ ํ์ผ์ ๋ค์ด๋ก๋ ๊ฐ๋ฅ
- ์ ๋ก๋ํ ํ์ผ ๋ฆฌ์คํธ๋ ์น ๋ธ๋ผ์ฐ์ ์์ ํ์ธ๊ฐ๋ฅ
Domain
Item
@Data
public class Item {
private Long itemId;
private String itemName;
private UploadFile attachFile;
private List<UploadFile> imageFiles;
}
@Data
public class UploadFile {
private String uploadFileName;
private String storeFileName;
public UploadFile(String uploadFileName, String storeFileName) {
this.uploadFileName = uploadFileName;
this.storeFileName = storeFileName;
}
}
- ์ํ ์์ด๋, ์ํ ์ด๋ฆ, ํ์ผ, ํ์ผ ๋ฆฌ์คํธ
- ํ์ผ์ UploadFileName๊ณผ StorFileName์ผ๋ก ๊ตฌ๋ถํ๊ธฐ ์ํด UploadFile ํด๋์ค๋ฅผ ์์ฑํด์ ํ์
์ผ๋ก ์ง์
- ์๋ฒ์๋ ๊ฐ์ ํ์ผ์ ์ด๋ฆ์ด ์๋ ๊ฐ ํ์ผ์ ์๋ณํ ์ ์๋๋ก UUID๋ฅผ ํตํด ์ ๋ก๋ ์์ StoreFileName๊ณผ, UploadFileName์ผ๋ก ๊ตฌ๋ถ์ง์์ต๋๋ค.
-
์๋ก ๋ค๋ฅธ ๊ณ ๊ฐ์ด ๊ฐ์ ํ์ผ์ด๋ฆ์ ์ ๋ก๋ ํ๋ ๊ฒฝ์ฐ ๊ธฐ์กด ํ์ผ ์ด๋ฆ๊ณผ ์ถฉ๋์ด ๋ ์ ์๊ธฐ ๋๋ฌธ์ ๊ณ ๊ฐ์ด ์ ๋ก๋ํ ํ์ผ๋ช ์ผ๋ก ์๋ฒ ๋ด๋ถ์ ํ์ผ์ ์ ์ฅํ๋ฉด ์๋ฉ๋๋ค.
ItemForm
@Data
public class ItemForm {
private Long itemId;
private String itemName;
private MultipartFile attachFile;
private List<MultipartFile> imageFiles;
}
- Item์ ์ ๋ก๋ ํ ๋ ์ฌ์ฉํ Form
- Item ๋๋ฉ์ธ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ์ํ ์์ด๋, ์ด๋ฆ, ํ์ผ, ํ์ผ๋ฆฌ์คํธ๊ฐ ์์ต๋๋ค.
- ํ์ผ์ ์ ์ก ํ ๋ MultipartFile ํ์ ์ฌ์ฉํ ์์
Item Repository
@Repository
public class ItemRepository {
private final Map<Long, Item> store = new HashMap<>();
private long sequence = 0L;
public Item save(Item item)
{
item.setItemId(++sequence);
store.put(item.getItemId(),item);
return item;
}
public Item findById(Long id)
{
return store.get(id);
}
}
- Item์ ์กฐํ, ์ ์ฅ. HashMap ์ฌ์ฉ
File Store
package hello.upload.file;
import hello.upload.domain.UploadFile;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@Component
public class FileStore {
@Value("${file.dir}")
private String fileDir;
// ์
๋ก๋ ๋๋ ๊ฒฝ๋ก + ํ์ผ์ด๋ฆ
public String getFullPath(String fileName)
{
return fileDir + fileName;
}
// ์
๋ก๋ ํ์ผ(์ค๋ฆฌ์ง๋ ํ์ผ์ด๋ฆ, ์คํ ์ด์ ์ฌ๋ผ๊ฐ ํ์ผ์ด๋ฆ)
// Form์ผ๋ก ๋ถํฐ POST๋ MultipartFile์ ์๋ฒ์ ์ ์ฅํ๊ณ UploadFile(์ค๋ฆฌ์ง๋ํ์ผ์ด๋ฆ, ์คํ ์ด์ ์ฌ๋ผ๊ฐ ํ์ผ์ด๋ฆ) ๋ฆฌํด
public UploadFile storeFile(MultipartFile multipartFile) throws IOException {
if(multipartFile.isEmpty())
{
return null;
}
String originalFilename = multipartFile.getOriginalFilename();
String storeFilename = createStoreFileName(originalFilename);
// transferTo๋ฅผ ํตํด ํ์ผ ์๋ฒ์ ์ ์ฅ (์๋ฒ์ ์ ์ฅ ํ ๋๋ UUID+.+ํ์ฅ์ )
multipartFile.transferTo(new File(getFullPath(storeFilename)));
return new UploadFile(originalFilename,storeFilename);
}
private String createStoreFileName(String originalFilename) {
int pos = originalFilename.lastIndexOf(".");
String uuid = UUID.randomUUID().toString();
String ext = originalFilename.substring(pos+1);
return uuid + "." + ext;
}
// ItemForm์ผ๋ก๋ถํฐ POST ๋ ํ์ผ ๋ฆฌ์คํธ๋ก๋ถํฐ ํ๋์ฉ iterate ํด์ ์๋ฒ์ ์ ์ฅํ๊ณ Item List์ ์ถ๊ฐํ๊ณ ๋ฆฌํด
public List<UploadFile> storeFiles(List<MultipartFile> multipartFiles) throws IOException {
List<UploadFile> storeFileResult = new ArrayList<>();
for (MultipartFile multipartFile : multipartFiles) {
if(!multipartFile.isEmpty())
{
storeFileResult.add(storeFile(multipartFile));
}
}
return storeFileResult;
}
}
- storeFile : Form์ผ๋ก๋ถํฐ ์ ์ก๋ ํ์ผ -> ( UUID.ํ์ฅ์ )๋ก ๋ณ๊ฒฝํด์ ํ์ผ์ ์๋ฒ(file.dir)์ ์ ์ฅํ๊ณ , Item Repository์๋ Item ์ ์ฅํด์ผ ํ๊ธฐ ๋๋ฌธ์ UploadFile ํ์์ผ๋ก ๋ณ๊ฒฝํด์ ๋ฆฌํด
- storeFiles : Form์ผ๋ก๋ถํฐ ์ ์ก๋ ํ์ผ ๋ฆฌ์คํธ -> iterator๋ฅผ ์ฌ์ฉํด ( UUID.ํ์ฅ์ )๋ก ๋ณ๊ฒฝํด์ ํ์ผ์ ์๋ฒ์ ํ๋์ฉ ์ ์ฅํ๊ณ , Item Repository์๋ Item ์ ์ฅํด์ผ ํ๊ธฐ ๋๋ฌธ์ UploadFile ํ์์ผ๋ก ๋ณ๊ฒฝํด์ List์ ์ถ๊ฐํด์ ๋ฆฌํด
- Controller์๋ฅผ ์ฐธ๊ณ .
Controller
ItemController
@Slf4j
@Controller
@RequiredArgsConstructor
public class ItemController {
private final ItemRepository itemRepository;
private final FileStore fileStore;
// Item ๋ฑ๋ก ํผ Get
@GetMapping("/items/new")
public String newItem(@ModelAttribute ItemForm form)
{
return "item-form";
}
// Item ๋ฑ๋ก ํผ์ ํตํด POST
@PostMapping("/items/new")
public String saveItem(@ModelAttribute ItemForm form, RedirectAttributes redirectAttributes) throws IOException {
UploadFile uploadFile = fileStore.storeFile(form.getAttachFile());
List<UploadFile> uploadFiles = fileStore.storeFiles(form.getImageFiles());
// ๋ฆฌํฌ์งํ ๋ฆฌ์ ์ ์ฅ
Item item = new Item();
item.setItemName(form.getItemName());
item.setAttachFile(uploadFile);
item.setImageFiles(uploadFiles);
itemRepository.save(item);
redirectAttributes.addAttribute("itemId",item.getItemId());
return "redirect:/items/{itemId}";
}
// Item ๋ทฐ
@GetMapping("/items/{itemId}")
public String itemView(@PathVariable Long itemId, Model model)
{
Item item = itemRepository.findById(itemId);
model.addAttribute("item",item);
return "item-view";
}
@ResponseBody
@GetMapping("/images/{fileName}")
public Resource downloadImage(@PathVariable String fileName) throws MalformedURLException {
return new UrlResource("file:" + fileStore.getFullPath(fileName));
}
// ๋ค์ด๋ก๋
@GetMapping("/attach/{itemId}")
public ResponseEntity<Resource> downloadAttach(@PathVariable Long itemId) throws MalformedURLException {
Item item = itemRepository.findById(itemId);
String uploadFileName = item.getAttachFile().getUploadFileName();
String storeFileName = item.getAttachFile().getStoreFileName();
UrlResource resource = new UrlResource("file:" + fileStore.getFullPath(storeFileName));
log.info("uploadFileName={}",uploadFileName);
String encode = UriUtils.encode(uploadFileName, StandardCharsets.UTF_8);
String contentDisposition = "attachment; filename=\"" + encode + "\"";
log.info("contentDisp = {}",contentDisposition);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,contentDisposition)
.body(resource);
}
}
- Item ๋ฑ๋ก ํผ, ์กฐํ ํผ ์ ๊ณต
- ๋ฑ๋ก ํผ์ ํตํ Item ๊ฐ์ฒด ๋ฑ๋ก
- ์กฐํ ํผ์ ํตํ Item ํ์ผ ์กฐํ ๋ฐ ๋ค์ด๋ก๋
- saveItem
// Item ๋ฑ๋ก ํผ์ ํตํด POST
@PostMapping("/items/new")
public String saveItem(@ModelAttribute ItemForm form, RedirectAttributes redirectAttributes) throws IOException {
// Form์ผ๋ก๋ถํฐ Post๋ ํ์ผ์ ์คํ ์ด์ ์ ์ฅํ๊ณ UploadFile ๋ฆฌํด -> ๋ฆฌํฌ์งํ ๋ฆฌ์ ์ ์ฅ
UploadFile uploadFile = fileStore.storeFile(form.getAttachFile());
// Form์ผ๋ก๋ถํฐ Post๋ ํ์ผ๋ฆฌ์คํธ๋ฅผ ์คํ ์ด์ ์ ์ฅํ๊ณ UploadFile List ๋ฆฌํด -> ๋ฆฌํฌ์งํ ๋ฆฌ์ ์ ์ฅ
List<UploadFile> uploadFiles = fileStore.storeFiles(form.getImageFiles());
// ๋ฆฌํฌ์งํ ๋ฆฌ์ ์ ์ฅ
Item item = new Item();
item.setItemName(form.getItemName());
item.setAttachFile(uploadFile);
item.setImageFiles(uploadFiles);
itemRepository.save(item);
redirectAttributes.addAttribute("itemId",item.getItemId());
return "redirect:/items/{itemId}";
}
- 1. @PostMapping saveItem์์ ItemForm์ ํตํด ๋ฐ์ ๋ฐ์ดํฐ๋ค์ @ModelAttribute ItemForm์ ํ๋กํผํฐ ์ฝ์
- 2. fileStore.storeFile, fileStore.storeFiles์ ํตํด 1๋ฒ์์ ์ฝ์ ๋ ํ์ผ๋ค์ ์ผ์ ์๋ฒ(file.dir)์ ์ ์ฅํ๊ณ ๋ฆฌํด๋ฐ์ UploadFile, UploadFiles List๋ฅผ ๋ฆฌํฌ์งํ ๋ฆฌ์ ์ ์ฅํฉ๋๋ค.
- ์ ์ฅํ๊ณ ๋๋ค /items/{itemId} (๋ฆฌ๋ค์ด๋ ์ ์ดํธ๋ฆฌ๋ทฐํธ์ ์ถ๊ฐ๋ itemId) ๋ก ๋ฆฌ๋ค์ด๋ ํธ
- itemView
@GetMapping("/items/{itemId}")
public String itemView(@PathVariable Long itemId, Model model)
{
Item item = itemRepository.findById(itemId);
model.addAttribute("item",item);
return "item-view";
}
- ์ ์ถ ๋ฒํผ ํด๋ฆญ ํ saveitem ๋ฉ์๋ ํธ์ถ ํ ๋ฆฌ๋ค์ด๋ ์ ๋ /Item/{ItemId} URI
- ๊ฒฝ๋ก ๋ณ์๋ก ๋์ด์จ Id๊ฐ์ ํตํด ํด๋น Id๊ฐ์ ๋ํ Item ์์ธ ์ ๋ณด๋ฅผ ๋ณด์ฌ์ฃผ๋ item view ๋ทฐํ ํ๋ฆฟ ํธ์ถํฉ๋๋ค.
- downloadImage
- ํ์ผ ๋ฆฌ์คํธ์ ์๋ ํ์ผ๋ค์ ํผ์์ th:each๋ฅผ ํตํด th:src๋ฅผ URI๋ก ๋ฟ๋ ค์ฃผ๋๋ฐ ์ปจํธ๋กค๋ฌ์์๋ ๋ฟ๋ ค์ค ์ด URI๋ฅผ @ResponseBody๋ก ์ฒ๋ฆฌํด์ ํด๋นํ์ผ์ UrlResource๋ก ํ๋ฉด์ ๋ณด์ฌ์ฃผ์์ต๋๋ค.
- downloadAttach
// ๋ค์ด๋ก๋
@GetMapping("/attach/{itemId}")
public ResponseEntity<Resource> downloadAttach(@PathVariable Long itemId) throws MalformedURLException {
Item item = itemRepository.findById(itemId);
String uploadFileName = item.getAttachFile().getUploadFileName();
String storeFileName = item.getAttachFile().getStoreFileName();
UrlResource resource = new UrlResource("file:" + fileStore.getFullPath(storeFileName));
log.info("uploadFileName={}",uploadFileName);
String encode = UriUtils.encode(uploadFileName, StandardCharsets.UTF_8);
// ๋ค์ด๋ก๋ ํ๊ธฐ ์ํด์ attachment; filename="๋ค์ด๋ฐ์ ํ์ผ์ด๋ฆ"์ Header CONTENT_DISPOSITION์ ์ค์
String contentDisposition = "attachment; filename=\"" + encode + "\"";
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,contentDisposition)
.body(resource); // resource ๋ค์ด
}
- ๋ค์ด๋ก๋ ๋ฐ์ ํ์ผ์ ์ฐพ๊ธฐ ์ํด ItemId๋ฅผ ํตํด Repository์์ Item์ ์กฐํํ๊ณ
- ์กฐํํ Item์ StoreFile์ด๋ฆ๊ณผ UploadFile ์ด๋ฆ์ ์ป์ด๋ ๋๋ค.
- ์ป์ด๋ธ StoreFile์ด๋ฆ์ผ๋ก ์๋ฒ์ ๋๋ ํ ๋ฆฌ(file.dir)๋ก ๋ถํฐ ํ์ผ ๋ฆฌ์์ค๋ฅผ ์ป์ด ๋ ๋๋ค.
- ๋ค์ด๋ก๋ ํ๊ธฐ ์ํด์ attachment; filename="์ ๋ก๋ ํ ํ์ผ์ด๋ฆ" ์ Header CONTENT_DISPOSITION์ ์ค์ ํด ์ฃผ์ด์ผ ํฉ๋๋ค. ( ํ์ผ ๋ค์ด๋ก๋์์ ํด๋ผ์ด์ธํธ๊ฐ ์ ๋ก๋ํ ํ์ผ ์ด๋ฆ ์ผ๋ก ๋ค์ด๋ก๋ ํ๊ธฐ ์ํด์ )
'๐ Backend > MVC Pattern' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
์๋ธ๋ฆฟ์ ์ด์ฉํ HTML Form ํ์ผ ์ ๋ก๋ (0) | 2023.03.30 |
---|---|
ํฌ๋งทํฐ(Formatter) (0) | 2023.03.29 |
ํ์ ์ปจ๋ฒํฐ(Type Converter) (0) | 2023.03.29 |
API์์์ ์์ธ ์ฒ๋ฆฌ (0) | 2023.03.28 |
Spring - ์๋ธ๋ฆฟ ์์ธ ์ฒ๋ฆฌ ( Exception ) (0) | 2023.03.28 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
Study Repository
rlaehddnd0422