개요
안녕하세요 빈코입니다. 오늘은 Java에서 파일 업로드하는 방법에 대해 알아보려고 합니다. UI에서 파일을 선택하고 업로드되는 과정을 보여주는 Progress bar를 표현하는 일련의 과정을 순서에 맞게 포스팅해 볼게요😄
UI 구성📒
가장 먼저 구현해야 할 것은 당연 Front 단이겠죠? Front단 설정은 간단합니다. input 타입을 file로 설정하여 사용자가 파일을 선택할 수 있는 파일 선택 버튼을 생성합니다. 그리고 저는 data-show-preview="false"를 설정하여 파일 미리 보기를 보여주지 않도록 설정하였습니다.
하위 코드로 아래와 같이 UI단을 구성하면 UI단은 끝이 납니다😊
<input type="file" class="file" id="input_file" name="input_file" data-show-preview="false">
JS 단 구성📙
$('#input_file').fileinput({
language: "ko",
showRemove: false,
browseOnZoneClick: true,
uploadUrl: 'json/file/upload.do',
uploadExtraData: function() {
return {
file_path : "/test/file"
};
},
slugCallback:function(text) {return text;},
required: true // 파일 필수 선택 옵션
});
위 코드는 JS단에서는 사용자가 파일을 선택하였을 때 FileInput() 플러그인을 초기화하여 선택한 요소에 대해 파일 업로드 기능을 제어하는 역할을 합니다. 첫 번째로, language를 한국어로 선택하고, showRemove 옵션을 false로 등록하여 파일 선택 후 표시되는 제거 버튼을 보이지 않게 처리하였습니다.
browseOnZoneClick 옵션을 true로 설정하여 업로드 영역을 클릭했을 때 파일 탐색기가 열리도록 설정합니다. 해당 값을 true로 설정하면 파일 입력 필드 외의 영역을 선택해도 파일 선택 대화상자가 열리게 됩니다.
uploadUrl은 파일을 업로드할 서버 Url을 설정하고, uploadExtraData는 업로드할 파일과 함께 추가 데이터를 서버로 보내는 역할을 합니다. 여기서는 파일을 저장할 위치인 file_path 데이터를 함께 전송했습니다.
slugCallback 옵션은 업로드할 파일의 이름을 반환하는 옵션인데, 여기서는 파일 이름 그대로 저장하도록 구현되어 있습니다. 만약 파일명에 공백을 하이픈 형태로 바꾸고 싶을 때, 해당 옵션을 사용하여 text를 사용자화 할 수 있습니다.
마지막으로 required 옵션은 파일 필수 선택 옵션입니다. 해당 옵션을 true로 설정하면 사용자가 파일을 선택하지 않으면, 해당 폼을 제출할 수 없도록 제한됩니다.
여기까지 구현이 되어 있다면 사용자가 UI를 통해 파일을 선택하고, 파일 선택 시 나오는 업로드 버튼을 이용하여 서버에 전송할 수 있게 됩니다. 이제 서버에서 해당 파일을 어떻게 처리할지 하단에서 이어서 포스팅해 볼게요😄
파일 서버에서 저장하기📘
@PostMapping(value = "json/file/upload.do")
public ResponseEntity<String> jsonFileUpload(@RequestParam Map<String, String> paramMap, Model model, HttpServletRequest request) throws Exception, IOException {
JSONObject json = new JSONObject();
int result = 1;
MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request;
Iterator<String> iterator = multipartHttpServletRequest.getFileNames();
MultipartFile multipartFile = null;
String storagePath = paramMap.get("file_path");
File file = new File(storagePath);
if (file.exists()) {
result = 2;
jsonObj.put("result", result);
return json;
} else {
file.mkdirs();
}
while (iterator.hasNext()) {
multipartFile = multipartHttpServletRequest.getFile(iterator.next());
if (!multipartFile.isEmpty()) {
String originalName = new String(multipartFile.getOriginalFilename().getBytes("8859_1"), "UTF-8");
File file = new File(storagePath, originalName);
multipartFile.transferTo(file);
}
}
return JSONResponseUtil.getJSONResponse(json);
}
위 코드는 Spring Framework에서 파일 업로드 처리를 위한 메서드입니다. 이 메서드는 위 JS 단에서 전송한 "json/file/upload.do" 경로로 POST 요청을 보낼 때 호출됩니다.
첫 번째로는 반환할 값인 JSONObject 타입의 json을 1로 설정하였습니다. 추후에, 만약 파일이 이미 존재할 경우 해당 값을 2로 설정하여 리턴할 예정이고, 해당 json 값을 이용하여 JS단에서 사용자에게 보여질 문구('파일 업로드 완료', '파일 업로드 실패')를 정하게 됩니다. 여기서 1은 파일 업로드 성공을 의미하고, 2는 이미 존재하는 파일을 의미하도록 설정하였습니다.
multipartHttpServletRequest는 HttpServletRequest를 MultipartHttpServletRequest로 캐스팅하여 파일 업로드를 처리할 수 있도록 합니다. 해당 객체는 파일 업로드와 관련된 메서드를 제공합니다.
이후에, 업로드된 파일들의 이름들을 가져올 수 있는 Iterator 객체를 생성했습니다. 해당 포스팅은 현재 1개의 파일만 전송하는 예시를 들었는데, 만약 여러 개의 파일들을 전송한다고 하더라도 Iterator 객체를 이용하여 모든 파일에 접근할 수 있도록 구성하였습니다.
MultipartFile multipartFile = null; 코드는 파일을 처리할 MultipartFile 객체를 초기화합니다. 실제 넘어온 파일들은 이 객체로 처리하게 됩니다. 그리고 JS단에서 넘긴 파일 경로를 storagePath 변수에 담았습니다. 이후에, storage 경로에 해당되는 파일을 생성합니다. 여기서 storagePath는 "/test/file"인데, 만약 해당 경로의 파일이 있으면 이미 존재하는 파일이기 때문에 값을 2로 설정하고 리턴하여 파일이 업로드되지 않게 구성하였고, 해당 경로에 파일이 없으면 해당 경로를 새로 만들게 구성하였습니다.
마지막으로, while(iterator.hasNext())를 이용하여 파일을 순차적으로 접근합니다. 위에서 선언한 multipartHttpServletRequest 객체의 getFile() 메서드를 이용하여 파일을 하나씩 꺼내고 그 파일을 multipartFile 객체로 받습니다.
여기서 isEmpty() 메서드를 이용하여 파일이 비어 있지 않다면(즉, 파일이 제대로 업로드되어 있으면), 해당 파일을 접근하여 getOriginalFilename() 메서드로 파일의 이름을 추출하고, 그 이름을 UTF-8로 변환하여 인코딩 문제를 방지하였습니다.
최종적으로 파일의 경로인 storagePath와 추출한 파일의 이름인 originalName을 합쳐서 최종 파일 경로를 지정하고, multipartFile.transferTo(file); 코드로 파일을 업로드하면 끝이 납니다😁
파일 업로드 후 처리📗
$('#input_file').on('fileuploaded', function(event, data, previewId, index) {
var response = data.response;
if(response.result==1) {
$.notify({
icon: 'fa fa-check',
message: "파일 업로드에 성공했습니다."
},{
type:"success"
});
}else if(response.result==2) {
$.notify({
icon: 'fa fa-exclamation-triangle',
message: "이미 같은 파일이 존재합니다."
});
$('#input_file').fileinput('clear').fileinput('enable');
}
});
파일 업로드 후 처리는 서버단에서 전송한 결과를 사용자에게 보여주는 역할을 합니다. FileInput 플러그인에서 fileuploaded는 파일 업로드가 완료되었을 때 실행됩니다. 첫 번째로, response에는 서버에서 결과값을 전송한 data.response를 값에 담습니다.
여기서 결과가 1일 경우에는 파일 업로드에 성공한 경우이고, 2인 경우에는 해당 파일이 이미 존재할 경우를 의미합니다. 저는 Notify.js 라이브러리를 사용하여 사용자에게 보여질 메시지를 출력하였습니다.
마지막으로, 이미 같은 파일이 존재할 경우에는 해당 메시지를 띄우고 다른 파일을 선택할 수 있도록 $('#input_file').fileinput('clear').fileinput('enable'); 코드를 사용합니다.
마치며
이로써 사용자에게 보여질 UI설정 부터 파일이 업로드 된 후의 사용자에게 보여 질 메시지까지 일련의 과정이 끝이 났습니다. 사실, 처음 파일 기능을 해보면 헷갈리는 부분이 많을 텐데 천천히 따라 하셔서 파일 업로드 기능을 구현해 보시면 좋을 것 같네요😊
'TIL' 카테고리의 다른 글
PostgerSQL Upsert 쿼리 개념 및 대용량 속도 차이 예제 (0) | 2024.11.23 |
---|---|
Java 회원가입 및 로그인 비밀번호 Hash 비교 방법 (0) | 2024.11.12 |
[JS] find,some,filter,map 등의 고차 함수 활용하기 (0) | 2024.10.11 |
js Shallow Copy(얕은 복사)와 Deep Copy(깊은 복사)의 차이 (0) | 2024.10.07 |
Java IP 유효성 검사 및 여러 유용한 함수 모음 (1) | 2024.09.24 |