본 게시물은 스스로의 공부를 위한 글입니다.
틀린 내용이 있을 수 있습니다.
Form
태그에 별도의 enctype
옵션이 없으면 이 방법으로 전송한다.username=kim&age=20
와 같이 & 로 구분해서 전송한다.하지만 파일을 업로드 하려면 문자가 아닌 바이너리 데이터를 전송해야 한다.
또한 파일뿐 아니라 이름, 나이 등도 함께 전송해야 한다.
즉, 첨부파일은 바이너리로, 이름과 나이는 문자로 동시에 전송해야 한다.
그래서 사용하는게
multipart/form-data
이다.
multipart/form-data
라는 전송 방식을 제공한다.enctype="multipart/form-data"
를 지정해야 한다------XXX
Content-Disposition: form-data; name="username"
kim
------XXX
Content-Disposition: form-data; name="file"; filename="intro.png"
Content-Type: image/png
1301390r13rjh13jr1309df13...
------XXX--
------XXX
로 전송 항목을 구분한것을 볼 수 있다. (실제론 무작위로 바운더리 문자가 정해지는데, HTTP 헤더를 보면 Content-Type: multipart/form-data; boundary=----xxxx
에서 확인할 수 있다.)multipart
!)HttpServletRequest
는 getParts()
라는 메소드를 제공한는데, multipart/form-data
전송 방식에서 각각 나누어진 부분을 받아서 확인할 수 있다.
다음 예시 코드를 통해 서블릿이 제공하는 메소드 기능들을 파악해보자.
@PostMapping("/upload")
public String saveFile(HttpServletRequest request) throws ServletException, IOException {
//특정 항목을 따로 뽑아낼 수 있다.
String itemName = request.getParameter("itemName");
//.getParts()로 모든 항목들을 collection형식으로 받을 수 있다.
Collection<Part> parts = request.getParts();
for (Part part : parts) {
//form에서 지정한 name을 받을 수 있다.
log.info("name={}", part.getName());
//각 항목마다 따로 존재하는 헤더값들을 collection으로 받을 수 있다.
Collection<String> headerNames = part.getHeaderNames();
for (String headerName : headerNames) { //각 항목 헤더들 출력
log.info("header {}: {}", headerName, part.getHeader(headerName));
}
//파일의 오리지널 이름을 얻을 수 있다. 파일이 아닌 그냥 문자의 경우 null이다.
log.info("submittedFileName={}", part.getSubmittedFileName());
log.info("size={}", part.getSize()); //각 파트의 사이즈를 얻을 수 있다.
InputStream inputStream = part.getInputStream(); //데이터 읽기
String fullPath = "/fileSave" + part.getSubmittedFileName();
part.write(fullPath); //경로만 지정해주면 파일을 저장할 수 있다.
}
MultipartFile
이라는 인터페이스로 멀티파트 파일을 매우 편리하게 지원한다.@RequestParam
으로 각 파트들을 받을 수 있다는게 큰 메리트이다.@ModelAttribute
으로도 받을 수 있다.@PostMapping("/upload")
public String saveFile(@RequestParam String itemName, @RequestParam MultipartFile file) throws IOException {
...
}
MultipartFile
주요 메서드file.getOriginalFilename()
: 업로드 파일 명file.transferTo(new File("PATH"))
: 파일 저장@Data
public class UploadFile {
private String uploadFileName;
private String storeFileName;
}
<form action="/item"method="post" enctype="multipart/form-data">
<ul>
<li>상품명 <input type="text" name="itemName"></li>
<li>첨부파일<input type="file" name="attachFile" ></li>
<li>이미지 파일들<input type="file" multiple="multiple" name="imageFiles" ></li>
</ul>
<input type="submit"/>
</form>
multipart/form-data
을 사용하려면 form
태그에 enctype="multipart/form-data"
가 들어가야된다.input
태그 속성으로 multiple="multiple"
을 넣으면 파일을 여러개 선택할 수 있다.List<MultipartFile>
로 @RequestParam
이든 @ModelAttribute
든 받으면 된다.<img>
에 이미지 보여주는 법@ResponseBody
@GetMapping("/images/{filename}")
public Resource showImage(@PathVariable String filename) throws
MalformedURLException {
return new UrlResource("file:" + file.getFullPath(filename));
}
<img src="/images/[파일이름]">
형식으로 쓰면 된다.UrlResource
는 file: FULLPATH
를 인자로 넘겨주면 실제 그곳에 있는 파일을 UrlResource
형태로 리턴해준다. 그럼 HTML의 img
에 보여질 수 있는거다.@GetMapping("/attach/{itemId}")
public ResponseEntity<Resource> downloadAttach(@PathVariable Long itemId) throws MalformedURLException {
//...itemId 이용해서 고객이 업로드한 파일 이름인 uploadFileName랑 서버 내부에서 사용하는 파일 이름인 storeFileName을 얻는다는 내용은 생략
UrlResource resource = new UrlResource("file:" + fileStore.getFullPath(storeFileName));
//한글 파일 이름이나 특수 문자의 경우 깨질 수 있으니 인코딩 한번 해주기
String encodedUploadFileName = UriUtils.encode(uploadFileName,
StandardCharsets.UTF_8);
//아래 문자를 ResponseHeader에 넣어줘야 한다. 그래야 링크를 눌렀을 때 다운이 된다.
//정해진 규칙이다.
String contentDisposition = "attachment; filename=\"" + encodedUploadFileName + "\"";
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition)
.body(resource);
}
<a href="/attach/[아이템이름] />
처럼 링크형식으로, 클릭했을 때 다운로드 받게 할 수 있다.<input type=file/>
로 파일을 받을 수 있다. 이때 form
에는 enctype="multipart/form-data"
속성이 있어야 한다.
multiple="multiple"
가 있으면 파일 여러개를 한번에 업로드 할 수 있다.스프링에선 @RequestParam
또는 @ModelAttribute
으로 MultipartFile file
을 받을 수 있다.
multiple="multiple"
이면 List<MultipartFile file>
로 받으면 된다.file.transferTo(new File("PATH")
을 이용해 파일을 저장할 수 있다.
file.getOriginalFilename()
으로 받을 수 있다.이미지를 HTML에 보여줄 땐 별도의 컨트롤러가 필요하다.
new UrlResource("file:" + file.getFullPath(filename));
을 이용해 Resource
를 리턴하자.
html에선 <img src=~~>
로 컨트롤러에서 넘어오는 Resource
를 보여줄 수 있다.
파일 다운 링크를 만들기 위해서도 별도의 컨트롤러가 필요하다.
Response Header
에 contentDisposition
를 넣어줘야 한다.body
값으론 Resource
를 넣어주면 된다.인프런의 '스프링 MVC 2편(김영한)'을 스스로 정리한 글입니다.
자세한 내용은 해당 강의를 참고해주세요
안녕하세요 질문 드립니다.
스프링 서버에서 클라이언트로 이미지를 여러개 전송하고 싶으면 어떻게 하나요? ResponseEntity에 Resource를 여러개 담을 수 있나요?