diff --git a/upload/src/main/java/hello/upload/controller/ItemController.java b/upload/src/main/java/hello/upload/controller/ItemController.java new file mode 100644 index 00000000..133d8321 --- /dev/null +++ b/upload/src/main/java/hello/upload/controller/ItemController.java @@ -0,0 +1,84 @@ +package hello.upload.controller; + +import hello.upload.domain.Item; +import hello.upload.domain.ItemRepository; +import hello.upload.domain.UploadFile; +import hello.upload.file.FileStore; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.Resource; +import org.springframework.core.io.UrlResource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; +import org.springframework.web.util.UriUtils; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.nio.charset.StandardCharsets; +import java.util.List; + +@Slf4j +@Controller +@RequiredArgsConstructor +public class ItemController { + + private final ItemRepository itemRepository; + private final FileStore fileStore; + + @GetMapping("/items/new") + public String newItem(@ModelAttribute ItemForm form) { + return "item-form"; + } + + @PostMapping("/items/new") + public String saveItem(@ModelAttribute ItemForm form, RedirectAttributes redirectAttributes) throws IOException { + UploadFile attachFile = fileStore.storeFile(form.getAttachFile()); + List storeImageFiles = fileStore.storeFiles(form.getImageFiles()); + + // 데이터베이스에 저장 + Item item = new Item(); + item.setItemName(form.getItemName()); + item.setAttachFile(attachFile); + item.setImageFiles(storeImageFiles); + itemRepository.save(item); + + redirectAttributes.addAttribute("itemId", item.getId()); + + return "redirect:/items/{itemId}"; + } + + @GetMapping("/items/{id}") + public String items(@PathVariable Long id, Model model) { + Item item = itemRepository.findById(id); + 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 downloadAttach(@PathVariable Long itemId) throws MalformedURLException { + Item item = itemRepository.findById(itemId); + String storeFileName = item.getAttachFile().getStoreFileName(); + String uploadFileName = item.getAttachFile().getUploadFileName(); + + UrlResource urlResource = new UrlResource("file:" + fileStore.getFullPath(storeFileName)); + log.info("uploadFilename={}", uploadFileName); + + String encodedUploadFilename = UriUtils.encode(uploadFileName, StandardCharsets.UTF_8); + String contentDisposition = "attachment; filename:\"" + encodedUploadFilename + "\""; + + return ResponseEntity.ok() + .header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition) + .body(urlResource); + } +} diff --git a/upload/src/main/java/hello/upload/controller/ItemForm.java b/upload/src/main/java/hello/upload/controller/ItemForm.java new file mode 100644 index 00000000..406b56d3 --- /dev/null +++ b/upload/src/main/java/hello/upload/controller/ItemForm.java @@ -0,0 +1,15 @@ +package hello.upload.controller; + +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +@Data +public class ItemForm { + + private Long itemId; + private String itemName; + private MultipartFile attachFile; + private List imageFiles; +} diff --git a/upload/src/main/java/hello/upload/domain/Item.java b/upload/src/main/java/hello/upload/domain/Item.java new file mode 100644 index 00000000..aac25312 --- /dev/null +++ b/upload/src/main/java/hello/upload/domain/Item.java @@ -0,0 +1,14 @@ +package hello.upload.domain; + +import lombok.Data; + +import java.util.List; + +@Data +public class Item { + + private Long id; + private String itemName; + private UploadFile attachFile; + private List imageFiles; +} diff --git a/upload/src/main/java/hello/upload/domain/ItemRepository.java b/upload/src/main/java/hello/upload/domain/ItemRepository.java new file mode 100644 index 00000000..7799ac0c --- /dev/null +++ b/upload/src/main/java/hello/upload/domain/ItemRepository.java @@ -0,0 +1,23 @@ +package hello.upload.domain; + +import org.springframework.stereotype.Repository; + +import java.util.HashMap; +import java.util.Map; + +@Repository +public class ItemRepository { + + private final Map store = new HashMap<>(); + private long sequence = 0L; + + public Item save(Item item) { + item.setId(++sequence); + store.put(item.getId(), item); + return item; + } + + public Item findById(Long id) { + return store.get(id); + } +} diff --git a/upload/src/main/java/hello/upload/domain/UploadFile.java b/upload/src/main/java/hello/upload/domain/UploadFile.java new file mode 100644 index 00000000..28430f99 --- /dev/null +++ b/upload/src/main/java/hello/upload/domain/UploadFile.java @@ -0,0 +1,12 @@ +package hello.upload.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class UploadFile { + + private String uploadFileName; + private String storeFileName; +} diff --git a/upload/src/main/java/hello/upload/file/FileStore.java b/upload/src/main/java/hello/upload/file/FileStore.java new file mode 100644 index 00000000..0b14690b --- /dev/null +++ b/upload/src/main/java/hello/upload/file/FileStore.java @@ -0,0 +1,56 @@ +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; + } + + public List storeFiles(List multipartFiles) throws IOException { + List storeFileResult = new ArrayList<>(); + for (MultipartFile multipartFile : multipartFiles) { + if (!multipartFile.isEmpty()) { + storeFileResult.add(storeFile(multipartFile)); + } + } + return storeFileResult; + } + + public UploadFile storeFile(MultipartFile multipartFile) throws IOException { + if (multipartFile.isEmpty()) { + return null; + } + + String originalFilename = multipartFile.getOriginalFilename(); + String storeFilename = createStoreFilename(originalFilename); + multipartFile.transferTo(new File(getFullPath(storeFilename))); + + return new UploadFile(originalFilename, storeFilename); + } + + private String createStoreFilename(String originalFilename) { + String ext = extractExt(originalFilename); + String uuid = UUID.randomUUID().toString(); + return uuid + "." + ext; + } + + private String extractExt(String originalFilename) { + int pos = originalFilename.lastIndexOf("."); + return originalFilename.substring(pos + 1); + } +} diff --git a/upload/src/main/resources/templates/item-form.html b/upload/src/main/resources/templates/item-form.html new file mode 100644 index 00000000..4d159ae6 --- /dev/null +++ b/upload/src/main/resources/templates/item-form.html @@ -0,0 +1,21 @@ + + + + + + +
+
+

상품 등록

+
+
+
    +
  • 상품명
  • +
  • 첨부파일
  • +
  • 이미지 파일들
  • +
+ +
+
+ + \ No newline at end of file diff --git a/upload/src/main/resources/templates/item-view.html b/upload/src/main/resources/templates/item-view.html new file mode 100644 index 00000000..71744c9d --- /dev/null +++ b/upload/src/main/resources/templates/item-view.html @@ -0,0 +1,17 @@ + + + + + + +
+
+

상품 조회

+
+ 상품명: 상품명
+ 첨부파일:
+ +
+ + \ No newline at end of file