Development/Java
[Library] 오렐리 COS 라이브러리 이미지 다중 업로드
컴공희
2024. 5. 4. 20:42
문제
- 저장은 모두 저장되지만, 한 개 파일만 순차적으로 읽을 수 있음.
- 파일이름을 while (files.hasMoreElements()) {} 을 통해서 모두 읽을 수 없음 .
- 파일이름을 통해 DB에 파일이름을 저장해야 했기 때문에 모든 파일의 정보가 필요했다.
소개
서블릿에서 이미지 업로드를 검색하면 가장 많이 나오는 라이브러리 중 하나가 오렐리의 COS 라이브러리이다.
엄청 오래되어 보이는 냄새..
이미지 업로드 구현을 위해서 다중 업로드 기능을 만들던 중
위에 처럼 다중 선택이 가능하도록 만들려고 코드에 multiple을 추가했다.
<input type="file" id="files" name="files" multiple>
이렇게 추가하면 file에 대한 값이 여러개 입력할 수 있도록 값이 전달된다.
-----------------------------1234567890123456789012345678
Content-Disposition: form-data; name="files[]"; filename="file1.txt"
Content-Type: text/plain
[내용이 여기에 들어갑니다. 파일 1의 내용]
-----------------------------1234567890123456789012345678
Content-Disposition: form-data; name="files[]"; filename="file2.txt"
Content-Type: text/plain
[내용이 여기에 들어갑니다. 파일 2의 내용]
-----------------------------1234567890123456789012345678--
하지만, 오렐리 COS 라이브러리를 사용하면 파일은 모두 저장되지만,
Enumeration files = mr.getFileNames() 을 했을 땐 항상 한 개만 들어있었다.
다른 인터넷 자료 처럼, 각각 다른 이름으로 여러개의 input type을 만들어서 했을 때는 문제 없이 작동한다.
<input type="file" id="files1" name="files1">
<input type="file" id="files2" name="files2">
원인
오렐리의 라이브러리를 직접 들어가보면 files는 name을 기준으로 담는다.
<input type="file" id="files" name="files" multiple>
로 입력한다면 같은 이름으로 파일을 넣게되니 마지막 파일이 덮어써져 한 개만 남게 되는 것이다.
해결 방안
오렐리를 사용하지 않고 아파치가 제공하는 Common FileUpload를 사용하자.
이전 코드
public static Map<String, String> fileSave(HttpServletRequest req) {
try {
Map<String, String> param = new HashMap<>();
List<String> fileNames = new ArrayList<>();
MultipartRequest mr = new MultipartRequest(req, FILE_PATH, 400000, "UTF-8", new DefaultFileRenamePolicy());
Enumeration params = mr.getParameterNames();
while (params.hasMoreElements()) {
String name = (String) params.nextElement();
String value = mr.getParameter(name);
log.info("name = {} value ={}", name, value);
param.put(name, value);
}
Enumeration files = mr.getFileNames();
while (files.hasMoreElements()) {
String name = (String) files.nextElement();
String fileName = mr.getFilesystemName(name);
String original = mr.getOriginalFileName(name);
String type = mr.getContentType(name);
File file = mr.getFile(name);
param.put("fileName", fileName);
fileNames.add(original);
log.info("요청 파라미터 이름 : {}", name);
log.info("실제 파일 이름 : {} ", original);
log.info("저장 파일 이름 : {}", fileName);
log.info("파일 콘텐츠 유형 : {}", type);
if (file != null) {
log.info("파일 크기 : {}", file.length());
}
}
req.setAttribute("fileNames", fileNames);
return param;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
이후 코드
public static Map<String, String> fileSave(HttpServletRequest req) {
try {
Map<String, String> param = new HashMap<>();
List<String> fileNames = new ArrayList<>();
// Create a factory for disk-based file items
DiskFileItemFactory factory = new DiskFileItemFactory();
// Set factory constraints
factory.setSizeThreshold(400000); // Set the maximum allowed size (in bytes) before a FileUploadException will be thrown.
factory.setRepository(new File(System.getProperty("java.io.tmpdir"))); // Set the repository location where files will be stored temporarily.
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);
// Parse the request
List<FileItem> items = upload.parseRequest(req);
// Process the uploaded items
for (FileItem item : items) {
if (item.isFormField()) { // Process regular form fields
String name = item.getFieldName();
String value = item.getString("UTF-8"); // Ensure UTF-8 encoding
log.info("name = {} value ={}", name, value);
param.put(name, value);
} else { // Process uploaded files
String fileName = item.getName();
String type = item.getContentType();
File file = new File(FILE_PATH, fileName);
try (InputStream fileContent = item.getInputStream();
OutputStream outputStream = new FileOutputStream(file)) {
IOUtils.copy(fileContent, outputStream); // Apache Commons IOUtils is used for stream copying
}
param.put("fileName", fileName);
fileNames.add(fileName);
log.info("실제 파일 이름 : {} ", fileName);
log.info("저장 파일 이름 : {}", file.getName());
log.info("파일 콘텐츠 유형 : {}", type);
log.info("파일 크기 : {}", file.length());
}
}
req.setAttribute("fileNames", fileNames);
return param;
} catch (FileUploadException | IOException e) {
throw new RuntimeException(e);
}
}
위는 gpt가 만들어준 코드... 놀랍다!
오늘도 삽집을 통해 배웠다...
어쩌면 난 노가다꾼이 아닌가?