sm 기술 블로그
[스프링부트] 다중 파일 업로드 본문
html
<div>
<input type="file" id="btnAtt" name="multiFile" multiple/>
<div id='att_zone' data-placeholder='파일을 첨부 하려면 파일 선택 버튼을 클릭하세요'></div>
</div>
mulilple로 인해 다중 파일이 업로드 가능하다.
script
<script>
// 여기는 솔직히 복붙이라 잘 몰라요 https://jobtc.tistory.com/43 여기서 퍼왔어요
(imageView = function imageView(att_zone, btn){
var attZone = document.getElementById(att_zone);
var btnAtt = document.getElementById(btn)
var sel_files = [];
// 이미지와 체크 박스를 감싸고 있는 div 속성
var div_style = 'display:inline-block;position:relative;'
+ 'width:150px;height:120px;margin:5px;border:1px solid #00f;z-index:1';
// 미리보기 이미지 속성
var img_style = 'width:100%;height:100%;z-index:none';
// 이미지안에 표시되는 체크박스의 속성
var chk_style = 'width:30px;height:30px;position:absolute;font-size:24px;'
+ 'right:0px;bottom:0px;z-index:999;background-color:rgba(255,255,255,0.1);color:#f00';
btnAtt.onchange = function(e){
var files = e.target.files;
var fileArr = Array.prototype.slice.call(files)
for(f of fileArr){
imageLoader(f);
}
}
// 탐색기에서 드래그앤 드롭 사용
attZone.addEventListener('dragenter', function(e){
e.preventDefault();
e.stopPropagation();
}, false);
attZone.addEventListener('dragover', function(e){
e.preventDefault();
e.stopPropagation();
}, false);
attZone.addEventListener('drop', function(e){
var files = {};
e.preventDefault();
e.stopPropagation();
var dt = e.dataTransfer;
files = dt.files;
for(f of files){
imageLoader(f);
}
}, false);
/*첨부된 이미리즐을 배열에 넣고 미리보기 */
imageLoader = function(file){
sel_files.push(file);
var reader = new FileReader();
reader.onload = function(ee){
let img = document.createElement('img');
img.setAttribute('style', img_style);
img.src = ee.target.result;
attZone.appendChild(makeDiv(img, file));
}
reader.readAsDataURL(file);
}
/*첨부된 파일이 있는 경우 checkbox와 함께 attZone에 추가할 div를 만들어 반환 */
makeDiv = function(img, file){
var div = document.createElement('div');
div.setAttribute('style', div_style)
var btn = document.createElement('input');
btn.setAttribute('type', 'button');
btn.setAttribute('value', 'x');
btn.setAttribute('delFile', file.name);
btn.setAttribute('style', chk_style);
btn.onclick = function(ev){
var ele = ev.srcElement;
var delFile = ele.getAttribute('delFile');
for(var i=0 ;i<sel_files.length; i++){
if(delFile== sel_files[i].name){
sel_files.splice(i, 1);
}
}
dt = new DataTransfer();
for(f in sel_files) {
var file = sel_files[f];
dt.items.add(file);
}
btnAtt.files = dt.files;
var p = ele.parentNode;
attZone.removeChild(p);
}
div.appendChild(img);
div.appendChild(btn);
return div
}
}
)('att_zone', 'btnAtt');
</script>
미리보기 또한 가능하다.
Service
@Service
@RequiredArgsConstructor
public class FileUploadService {
private final FilesRepository filesRepository;
private final ArticleService articleService;
@Async
public void doUpload(ArticleWriteForm articleWriteForm, List<MultipartFile> multiFileList, HttpServletRequest request, HttpSession session) {
String root = System.getProperty("user.dir") + "\\src\\main\\resources\\static\\uploadFiles";
// 아래 두 줄은 경로가 실제로 존재하는지 확인한다.
// 만약 실제로 존재하지 않는다면 폴더를 생성한다. (mkdir가 폴더 생성이다.)
File fileCheck = new File(root);
if (!fileCheck.exists()) fileCheck.mkdirs();
//원래 파일의 이름 -> 수정된 파일의 이름을 여러개 담기위해 리스트로 만듬
List<Map<String, String>> fileList = new ArrayList<>();
for (int i = 0; i < multiFileList.size(); i++) {
// 파일의 본래이름을 가져옴
String originFile = multiFileList.get(i).getOriginalFilename();
// 파일형식을 ext에 뽑아냄 ex) 나는이미지.png 에서 .png를 뽑아서 ext에 저장
String ext = originFile.substring(originFile.lastIndexOf("."));
// uuid는 네트워크 상에서 고유성이 보장되는 id를 만들기 위한 규약이다.
// 다시말해 파일들이 서로 이름을 겹치지 않게 하기 위해서 만든것이다. 마지막에 ext를 붙여 파일형식을 정의해준다.
String changeFile = UUID.randomUUID().toString() + ext;
// 본래 이름을 Key, 바꾼 이름을 Value로 해서 map에 저장한다.
Map<String, String> map = new HashMap<>();
map.put("originFile", originFile);
map.put("changeFile", changeFile);
// 수정된 파일의 이름들을 담고 있는 map을 리스트에 저장한.
fileList.add(map);
}
// 파일 업로드를 진행함
try {
for (int i = 0; i < multiFileList.size(); i++) {
/*
transferTo 는 파일을 저장하는 함수이다.
파일 리스트에서 파일을 뽑고, 그 파일을 지정한 경로에 저장한다.
*/
File uploadFile = new File(root + "\\" + fileList.get(i).get("changeFile"));
multiFileList.get(i).transferTo(uploadFile);
}
// 위 작업이 완료되었다면 성공적으로 파일을 저장했다는 뜻으로, 이제 글을 생성해야한다.
// 아래에 있는 함수는 현재 클래스에서 지원한다.
// 파일 목록, 세션정보, 받아온 제목과 내용을 넘긴다.
uploadDB(fileList, session, articleWriteForm);
// 확인용...
System.out.println("다중 파일 업로드 성공!");
} catch (IllegalStateException | IOException e) {
// 확인용...
System.out.println("다중 파일 업로드 실패 ㅠㅠ");
// 만약 업로드 실패하면 파일 삭제
for (int i = 0; i < multiFileList.size(); i++) {
new File(root + "\\" + fileList.get(i).get("changeFile")).delete();
}
// 오류 추적하는거임
e.printStackTrace();
}
}
// 파일 DB에 업로드 할거임.
private void uploadDB(List<Map<String, String>> fileName, HttpSession session, ArticleWriteForm articleWriteForm) {
// 먼저 글쓰기를 진행함. 로그인한 아이디와 제목, 내용을 넘긴다. (로그인한 아이디를 넘긴 이유는 누가 글을 썼는지 알기 위해서이다.)
Article aritcle = articleService.doWrite((long) session.getAttribute("loginedUserId"), articleWriteForm.getTitle(), articleWriteForm.getBody());
// 파일을 만들어서 DB에 저장하는 과정
for (Map<String, String> file : fileName) {
Files files = new Files();
files.setFilename(file.get("changeFile"));
files.setArticle(aritcle);
filesRepository.save(files);
}
}
}
DB
CREATE TABLE files(
id BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
`filename` TEXT,
article_id BIGINT UNSIGNED NOT NULL //파일들을 연결하고자 하는 객체의 아이디
);
'스프링부트' 카테고리의 다른 글
[스프링부트] Query 사용 (JPA) (0) | 2022.08.11 |
---|---|
[스프링부트] thymeleaf로 클래스 변경 (0) | 2022.08.10 |
[스프링부트] 403 에러 (0) | 2022.08.09 |
[스프링부트] 검색기능 (JPA) (0) | 2022.08.08 |
[스프링부트] 이메일 보내기 (0) | 2022.07.30 |
Comments