파일 : T_UPLOAD_INFO 판매점 : T_SALES_STORE_INFO 발전시뮬레이션 ITEM : T_ITEM_INFO ITEM 조회 : T_ITEM_INFO
387 lines
12 KiB
Java
387 lines
12 KiB
Java
package com.interplug.qcast.biz.file;
|
|
|
|
import com.interplug.qcast.biz.file.dto.FileRequest;
|
|
import com.interplug.qcast.biz.file.dto.FileResponse;
|
|
import com.interplug.qcast.config.Exception.ErrorCode;
|
|
import com.interplug.qcast.config.Exception.QcastException;
|
|
import com.interplug.qcast.config.message.Messages;
|
|
import com.interplug.qcast.util.ZipFileManager;
|
|
import jakarta.servlet.http.HttpServletRequest;
|
|
import jakarta.servlet.http.HttpServletResponse;
|
|
import java.io.*;
|
|
import java.net.URLConnection;
|
|
import java.net.URLEncoder;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.*;
|
|
import java.util.stream.Collectors;
|
|
import lombok.RequiredArgsConstructor;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.util.FileCopyUtils;
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
|
|
|
@Slf4j
|
|
@Service
|
|
@RequiredArgsConstructor
|
|
public class FileService {
|
|
|
|
Messages message;
|
|
|
|
private final FileMapper fileMapper;
|
|
|
|
@Value("${file.ini.root.path}")
|
|
private String baseDirPath;
|
|
|
|
private ZipFileManager zipFileManager;
|
|
|
|
/**
|
|
* 파일 업로드
|
|
*
|
|
* @param request
|
|
* @param fileRequest
|
|
* @return
|
|
* @throws Exception
|
|
*/
|
|
public List<FileRequest> getUploadFileList(HttpServletRequest request, FileRequest fileRequest)
|
|
throws Exception {
|
|
List<FileRequest> saveFileList = new ArrayList<>();
|
|
List<MultipartFile> multipartFileList = new ArrayList<>();
|
|
|
|
if (!MultipartHttpServletRequest.class.isAssignableFrom(request.getClass())) {
|
|
return new ArrayList<>();
|
|
}
|
|
|
|
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
|
|
Map<String, List<MultipartFile>> mapMultipart = multipartRequest.getMultiFileMap();
|
|
if (mapMultipart.isEmpty()) {
|
|
return null;
|
|
}
|
|
|
|
String strParamKey;
|
|
for (String s : mapMultipart.keySet()) {
|
|
strParamKey = s;
|
|
multipartFileList.addAll(mapMultipart.get(strParamKey));
|
|
}
|
|
|
|
int iFileCnt = multipartFileList.size();
|
|
if (iFileCnt > 0) {
|
|
int iFileSeq = 1;
|
|
|
|
String strSeparator = File.separator;
|
|
String strFileFolderPath =
|
|
baseDirPath + strSeparator + fileRequest.getObjectNo() + strSeparator;
|
|
|
|
// planNo가 있는 경우
|
|
if (fileRequest.getPlanNo() != null && !fileRequest.getPlanNo().isEmpty()) {
|
|
strFileFolderPath += fileRequest.getPlanNo() + strSeparator;
|
|
}
|
|
|
|
log.info("### fileFolderPath : {}", strFileFolderPath);
|
|
|
|
// 파일 폴더 생성
|
|
makeFileFolder(strFileFolderPath);
|
|
|
|
for (MultipartFile multipartFile : multipartFileList) {
|
|
if (!multipartFile.isEmpty()) {
|
|
|
|
// 파일 확장자 발췌 및 확장자 소문자 변환
|
|
String strFileExt = multipartFile.getOriginalFilename();
|
|
if (strFileExt != null && !strFileExt.isEmpty()) {
|
|
strFileExt = strFileExt.substring(strFileExt.lastIndexOf(".") + 1).toLowerCase().trim();
|
|
} else {
|
|
strFileExt = "";
|
|
}
|
|
|
|
// 파일 확장자 및 사이즈 검증
|
|
List<String> listExtension = this.getFileExtension();
|
|
if (!validFileExtension(listExtension, strFileExt)) {
|
|
multipartFile.getInputStream().close();
|
|
continue;
|
|
}
|
|
|
|
String strSrcFileNm = multipartFile.getOriginalFilename();
|
|
strSrcFileNm = this.getUniqueFileName(strFileFolderPath, strSrcFileNm);
|
|
File file = new File(strFileFolderPath, strSrcFileNm);
|
|
|
|
multipartFile.transferTo(file);
|
|
|
|
FileRequest fileSaveReq = new FileRequest();
|
|
fileSaveReq.setObjectNo(fileRequest.getObjectNo());
|
|
fileSaveReq.setPlanNo(fileRequest.getPlanNo());
|
|
fileSaveReq.setCategory(fileRequest.getCategory());
|
|
fileSaveReq.setFaileName(strSrcFileNm);
|
|
fileSaveReq.setUserId(fileRequest.getUserId());
|
|
saveFileList.add(fileSaveReq);
|
|
|
|
iFileSeq++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return saveFileList;
|
|
}
|
|
|
|
/**
|
|
* 파일 확장자 검증
|
|
*
|
|
* @param listExtension
|
|
* @param strFileExt
|
|
* @return
|
|
* @throws Exception
|
|
*/
|
|
private boolean validFileExtension(List<String> listExtension, String strFileExt)
|
|
throws Exception {
|
|
boolean bResult = true;
|
|
|
|
try {
|
|
|
|
if (strFileExt == null || strFileExt.isEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
for (String s : listExtension) {
|
|
strFileExt = strFileExt.toLowerCase();
|
|
|
|
// 업로드 가능한 파일 확장자 검증
|
|
if (s.equals(strFileExt)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
log.error("### FileService - validFileExtension : Exception Error");
|
|
return false;
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
// 업로드 가능한 파일 확장자 조회
|
|
public List<String> getFileExtension() {
|
|
return Arrays.asList(
|
|
"mp3", "wma", "wav", "m4a", "3gp", "hwp", "doc", "docx", "ppt", "pptx", "zip", "xls",
|
|
"xlsx", "pdf", "txt", "jpg", "gif", "png");
|
|
}
|
|
|
|
// 파일 폴더 생성
|
|
private void makeFileFolder(String strMakeDir) {
|
|
try {
|
|
File dir = new File(strMakeDir.replace("//", "/"));
|
|
if (!dir.exists()) {
|
|
if (!dir.mkdirs()) {
|
|
log.error("### Failed to create directories: {}", strMakeDir);
|
|
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR);
|
|
}
|
|
}
|
|
} catch (Exception e) {
|
|
log.error("### FileService - makeFileFolder : Exception Error");
|
|
}
|
|
}
|
|
|
|
// 파일정보 저장 및 삭제
|
|
public Integer setFile(List<FileRequest> saveFilelist, List<FileRequest> deleteFilelist)
|
|
throws Exception {
|
|
|
|
Integer iResult = 0;
|
|
|
|
// 파일 삭제
|
|
if (deleteFilelist != null && !deleteFilelist.isEmpty()) {
|
|
for (FileRequest fileDeleteReq : deleteFilelist) {
|
|
if (!"".equals(fileDeleteReq.getObjectNo())) {
|
|
fileMapper.deleteFile(fileDeleteReq); // 파일 삭제
|
|
}
|
|
}
|
|
}
|
|
|
|
// 파일 저장
|
|
if (saveFilelist != null && !saveFilelist.isEmpty()) {
|
|
for (FileRequest fileInsertReq : saveFilelist) {
|
|
if (!"".equals(fileInsertReq.getObjectNo()) && !"".equals(fileInsertReq.getCategory())) {
|
|
iResult += fileMapper.insertFile(fileInsertReq);
|
|
fileMapper.insertFileInfo(fileInsertReq);
|
|
}
|
|
}
|
|
}
|
|
|
|
return iResult;
|
|
}
|
|
|
|
/**
|
|
* 파일 1건 다운로드
|
|
*
|
|
* @param request
|
|
* @param response
|
|
* @param fileRequest
|
|
* @throws Exception
|
|
*/
|
|
public void downloadFile(
|
|
HttpServletRequest request, HttpServletResponse response, FileRequest fileRequest)
|
|
throws Exception {
|
|
|
|
System.out.println("fileRequest>>>" + fileRequest.toString());
|
|
|
|
// 필수값 체크
|
|
if (fileRequest.getObjectNo() == null || fileRequest.getObjectNo().isEmpty()) {
|
|
throw new QcastException(
|
|
ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Object No"));
|
|
} else if (fileRequest.getNo() == 0) {
|
|
throw new QcastException(
|
|
ErrorCode.INVALID_INPUT_VALUE, message.getMessage("common.message.required.data", "No"));
|
|
}
|
|
|
|
// 파일정보 조회
|
|
FileResponse fileResponse = fileMapper.selectFile(fileRequest);
|
|
if (fileResponse == null) {
|
|
throw new QcastException(
|
|
ErrorCode.NOT_FOUND, message.getMessage(" common.message.file.download.exists"));
|
|
}
|
|
|
|
try {
|
|
// 첨부파일 물리적 경로
|
|
String strSeparator = File.separator;
|
|
String filePath = baseDirPath + strSeparator + fileResponse.getObjectNo();
|
|
if (fileResponse.getPlanNo() != null && !fileResponse.getPlanNo().isEmpty()) {
|
|
filePath += strSeparator + fileResponse.getPlanNo();
|
|
}
|
|
filePath += strSeparator + fileResponse.getFaileName();
|
|
|
|
File file = new File(filePath);
|
|
if (!file.exists()) {
|
|
log.error("### File not found: {}", filePath);
|
|
throw new QcastException(ErrorCode.INTERNAL_SERVER_ERROR);
|
|
}
|
|
|
|
String mimeType = URLConnection.guessContentTypeFromName(file.getName());
|
|
if (mimeType == null) {
|
|
mimeType = "application/octet-stream";
|
|
}
|
|
|
|
String originalFileName = fileResponse.getFaileName();
|
|
String encodedFileName =
|
|
URLEncoder.encode(originalFileName, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
|
|
|
|
response.setHeader("Content-Transfer-Encoding", "binary;");
|
|
response.setHeader("Pragma", "no-cache;");
|
|
response.setHeader("Expires", "-1;");
|
|
response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"");
|
|
response.setContentType(mimeType);
|
|
response.setContentLength((int) file.length());
|
|
|
|
try (InputStream inputStream = new BufferedInputStream(new FileInputStream(file))) {
|
|
FileCopyUtils.copy(inputStream, response.getOutputStream());
|
|
} catch (IOException e) {
|
|
throw new QcastException(
|
|
ErrorCode.INTERNAL_SERVER_ERROR,
|
|
message.getMessage("common.message.file.download.error"));
|
|
}
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 파일 N건 ZIP 다운로드
|
|
*
|
|
* @param request
|
|
* @param response
|
|
* @param fileRequest
|
|
* @throws Exception
|
|
*/
|
|
public void downloadZipFile(
|
|
HttpServletRequest request, HttpServletResponse response, FileRequest fileRequest)
|
|
throws Exception {
|
|
|
|
// 필수값 체크
|
|
if (fileRequest.getObjectNo() == null || fileRequest.getObjectNo().isEmpty()) {
|
|
throw new QcastException(
|
|
ErrorCode.INVALID_INPUT_VALUE,
|
|
message.getMessage("common.message.required.data", "Object No"));
|
|
}
|
|
|
|
String strZipFileName = fileRequest.getZipFileName();
|
|
if (strZipFileName == null || strZipFileName.isEmpty()) {
|
|
strZipFileName = "Download";
|
|
}
|
|
|
|
// 파일 조회
|
|
List<FileResponse> fileList = fileMapper.selectFileList(fileRequest);
|
|
if (fileList == null || fileList.size() == 0) {
|
|
throw new QcastException(
|
|
ErrorCode.NOT_FOUND, message.getMessage(" common.message.file.download.exists"));
|
|
}
|
|
|
|
// 첨부파일 물리적 경로
|
|
FileResponse fileResponse = fileList.get(0);
|
|
String zipFilePath = fileResponse.getObjectNo();
|
|
String filePath = baseDirPath + File.separator + fileResponse.getObjectNo() + File.separator;
|
|
if (fileResponse.getPlanNo() != null && !fileResponse.getPlanNo().isEmpty()) {
|
|
zipFilePath += File.separator + fileResponse.getPlanNo();
|
|
filePath += fileResponse.getPlanNo() + File.separator;
|
|
}
|
|
|
|
String finalFilePath = filePath;
|
|
String finalZipFilePath = zipFilePath;
|
|
List<Map<String, String>> listFile =
|
|
fileList.stream()
|
|
.map(
|
|
file -> {
|
|
Map<String, String> map = new HashMap<>();
|
|
map.put("directory", finalZipFilePath);
|
|
map.put("filename", finalFilePath + file.getFaileName());
|
|
return map;
|
|
})
|
|
.collect(Collectors.toList());
|
|
|
|
// zip 파일로 변환
|
|
zipFileManager.createZipFile(response, strZipFileName, listFile);
|
|
}
|
|
|
|
public Integer deleteFile(FileRequest fileRequest) throws Exception {
|
|
Integer iResult = 0;
|
|
|
|
// 첨부파일 논리적 삭제
|
|
iResult = fileMapper.deleteFile(fileRequest); // 파일 삭제
|
|
|
|
return iResult;
|
|
}
|
|
|
|
public List<FileRequest> fileUpload(HttpServletRequest request, FileRequest fileRequest)
|
|
throws Exception {
|
|
List<FileRequest> saveFileList = this.getUploadFileList(request, fileRequest);
|
|
// Integer resultCnt = this.setFile(saveFileList, null);
|
|
return saveFileList;
|
|
}
|
|
|
|
public String getUniqueFileName(String uploadDir, String fileName) {
|
|
File dir = new File(uploadDir);
|
|
if (!dir.exists()) {
|
|
dir.mkdirs(); // 디렉터리가 없으면 생성
|
|
}
|
|
|
|
String name = fileName;
|
|
String extension = "";
|
|
|
|
// 파일명과 확장자 분리
|
|
int dotIndex = fileName.lastIndexOf(".");
|
|
if (dotIndex >= 0) {
|
|
name = fileName.substring(0, dotIndex);
|
|
extension = fileName.substring(dotIndex);
|
|
}
|
|
|
|
File file = new File(uploadDir, fileName);
|
|
int counter = 1;
|
|
|
|
// 파일명이 중복될 경우 번호를 붙임
|
|
while (file.exists()) {
|
|
String newFileName = name + "_" + counter + extension;
|
|
file = new File(uploadDir, newFileName);
|
|
counter++;
|
|
}
|
|
|
|
return file.getName();
|
|
}
|
|
}
|