[ 사진 업로드 하기 ]
사진 업로드 버튼을 누르면 터진다. 고치자
[ PicController ]
@Controller public class PicController { @PostMapping("/upload") public String upload() { return "redirect:/"; }
[ PicRequest ]
사진 업로드를 하려면 DTO가 필요하다!
package com.mtcoding.fileapp.pic; import lombok.Data; import org.springframework.web.multipart.MultipartFile; public class PicRequest { @Data public static class UploadDTO { private String title; //키값이 타이틀 private MultipartFile imgFile; //키값이 imgFile } }
"키값이 타이틀", "키값이 imgFile" 이라는 표현은 UploadDTO 클래스의 각 필드명을 가리킨다. 이 필드명들은 데이터를 전달할 때 사용되는 키로, 이 키를 통해 데이터를 가져오거나 설정할 수 있다. 여기에서 title과 imgFile은 UploadDTO 클래스의 키값 혹은 필드명이라고 볼 수 있다. title: 업로드할 사진의 타이틀 정보를 담는다. 예를 들어, 사용자가 업로드하는 사진에 '여행사진'이라는 타이틀을 붙였다면, '여행사진'이라는 값이 title 필드에 저장된다. imgFile: 실제로 업로드 되는 이미지 파일 정보를 담는다. 사용자가 선택한 이미지 파일이 imgFile 필드에 저장된다. 따라서 이 UploadDTO 객체를 통해 업로드하는 사진의 타이틀과 이미지 파일 정보를 한 번에 전달할 수 있다.
[ PicController (확인 위해 sout) ]
@Controller public class PicController { @PostMapping("/upload") public String upload(PicRequest.UploadDTO requestDTO) { System.out.println(requestDTO.getTitle()); MultipartFile imgFile = requestDTO.getImgFile(); //객체를 받고 //base24로 변환된 문자열? //컨버터해서 들고있다. 바이트로 받아야하니까 System.out.println(imgFile.getContentType()); //무슨 파일인지 확인해보고 System.out.println(imgFile.getOriginalFilename()); return "redirect:/"; }
둘 다 문자열로 컨버트 되어야하니까 base24로 보낸다. 사진은 문자열이 아니라 바이트! 웹에서 파일(특히 이미지와 같은 미디어 파일)을 전송할 때, 이 파일들은 기본적으로 바이트 데이터로 존재한다. 하지만 HTTP를 통해 데이터를 전송할 때는 문자열 형태로 전송되는 것이 일반적. 따라서 바이트 형태의 이미지 데이터를 안전하게 문자열로 변환하여 전송하고, 받는 쪽에서는 이 문자열을 다시 원래의 바이트 데이터로 변환해야 한다. 이 과정에서 Base64 인코딩 방식이 자주 사용 된다! 이미지 파일을 바이트 배열로 읽어옴 -> 바이트 배열을 Base64로 인코딩하여 문자열로 변환 -> 변환된 문자열을 HTTP를 통해 전송 -> Base64로 인코딩된 문자열 데이터를 받음 -> 문자열을 Base64 디코딩하여 원래의 바이트 배열로 변환 -> 바이트 배열을 사용하여 이미지 파일을 복원하거나 필요한 작업을 수행 그걸 MultipartFile imgFile = requestDTO.getImgFile(); 이 객체가 알아서 해준다! 사진은 바이트!!!
DB에는 내 서버 측의 파일 경로만 넣을 것!
파일 쓰기 - 이 코드의 목적 : static 폴더 안에 사진 뿌리기
사용자가 웹 애플리케이션을 통해 파일을 업로드하면, 서버는 이 파일을 받아 static 폴더 같은 정적 리소스를 제공하는 디렉토리에 저장한다. 실제 파일을 서버의 하드디스크에 저장하고, 그 파일의 경로나 이름은 데이터베이스(DB)에 저장 -> 파일 자체가 아니라 경로나 파일명만 저장하는 이유는 데이터베이스에 실제 파일 데이터를 저장하는 것이 비효율적이고 성능에 부정적인 영향을 줄 수 있기 때문
DB에는 이거 2개(title과 imgFilename)만 저장할 것이다!
@Controller public class PicController { @PostMapping("/upload") public String upload(PicRequest.UploadDTO requestDTO) { String title = requestDTO.getTitle(); MultipartFile imgFile = requestDTO.getImgFile(); String imgFilename = imgFile.getOriginalFilename(); //맛집.png가 될 것 Path imgPath = Paths.get(imgFilename); //이렇게 path를 만듬 // Path imgPath = Paths.get("a/"+imgFilename); //경로가 a라는 폴더 안에 있으면 이런 식으로 함 try { Files.write(imgPath, imgFile.getBytes()); //파일의 내용을 바이트 배열로 읽어옴 } catch (IOException e) { throw new RuntimeException(e); } return "redirect:/"; }
Path imgPath = Paths.get(imgFilename); -> 경로 설정하는 코드
파일의 경로나 이름은 데이터베이스(DB)에 저장하기 때문에 경로를 설정하는 코드가 필요
[ 화면 확인 ]
사진 업로드를 했는데... 오잉? 이상한 곳에 들어가버렸다. -> 경로 이상 여기에 들어가버리면 html 폴더에서 찾을 수가 없다. html에서 찾으려면 'static 폴더' 안에 무조건 있어야한다!
[ 외울 필요 없이 짧게 테스트만 해보자. 프로젝트에 따라 다 다름 ]
경로 앞에 [ / ] 를 붙이면?
Path imgPath = Paths.get("/" + imgFilename);
제---일 최상위 경로로 들어왔다.. 즉, \D: 드라이브에 들어가 있다.
경로 앞에 [ ./ ] 를 붙이면? ( ./ = 현재 경로)
Path imgPath = Paths.get("./" + imgFilename);
fileapp 폴더 내부로 들어왔다.
./했는데 study_lec에서 실행되고 있다면 현재 경로는 study_lec이란 말이다
[ static 경로에 넣기 ]
Path imgPath = Paths.get("./src/main/resources/static/" + imgFilename);
왜 static에 넣을까? → 애만 외부에서 접근이 가능하기 때문
다른 폴더를 쓰고 싶으면 그 폴더를 외부에 노출할 수 있게 스프링에서 따로 설정을 해줘야함
들어왔다!
[ upload 경로에 넣기 ]
Path imgPath = Paths.get("./src/main/resources/static/upload/" + imgFilename);
static 폴더는 외부에서 파일명으로 바로 접근 가능하기 때문에 uploadCheck.mustache 에서 <img src="/upload/hello.png" width="500" height="500" alt="사진없음"> 라고 쓴다.
그러니까
<img src="/upload/{{fileName}}" width="500" height="500" alt="사진없음"> fileName 이 부분만 DB에서 들고 오자. 안그러면 DB에 전부 UPDATE 쳐서 수정해야함
파일명을 다르게 전송해야 한다
고객이 hello와 hello 파일을 2개 저장해버리면 ... 안됨 그래서 롤링이 필요하다. (hello1이나 hello2 처럼 저장되는...) -> 해쉬가 필요하다!!! 해쉬맵으로 저장한다!
Share article