package froala.editor;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import egovframework.com.cmm.util.EgovResourceCloseHelper;
import egovframework.rte.fdl.cmmn.exception.EgovBizException;
import froala.editor.file.FileOptions;
import froala.editor.image.ImageOptions;
import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.Thumbnails.Builder;
/**
* File functionality.
*
* @author florin@froala.com
*/
@Component
public final class File {
private static final Logger LOGGER = LoggerFactory.getLogger(File.class);
/**
* Content type string used in http multipart.
*/
public static final String multipartContentType = "multipart/form-data";
/**
* Private constructor.
*/
private File() {
}
/**
* File default options.
*/
public static final FileOptions defaultOptions = new FileOptions();
/**
* Uploads a file to disk.
*
* @param req
* Servlet HTTP request.
* @param fileRoute
* Route Server route where the file will be uploaded. This route
* must be public to be accesed by the editor.
* @return Object with link.
* @throws EgovBizException
*/
public static EditorFileVO upload(HttpServletRequest req, String fileRoute) throws EgovBizException {
return upload(req, fileRoute, defaultOptions);
}
/**
* Uploads a file to disk.
*
* @param req
* Servlet HTTP request.
* @param fileRoute
* Server route where the file will be uploaded. This route must
* be public to be accesed by the editor.
* @param options
* File options. Defaults to {@link #defaultOptions} which has
*
* Fieldname: "file"
* Validation:
*
* - Extensions: "txt", "pdf", "doc"
* - Mime Types: "text/plain", "application/msword",
* "application/x-pdf", "application/pdf"
*
* @return Object with link.
* @throws EgovBizException
*/
public static EditorFileVO upload(HttpServletRequest req, String fileRoute, FileOptions options) throws EgovBizException {
if (options == null) {
options = defaultOptions;
}
if (req.getContentType() == null || req.getContentType().toLowerCase().indexOf(multipartContentType) == -1) {
throw new EgovBizException("Invalid contentType. It must be " + multipartContentType);
}
MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest)req;
MultipartFile file = multipartHttpServletRequest.getFile(options.getFieldname());
// servlet 3.0
//Part filePart = req.getPart(options.getFieldname());
if (file == null) {
throw new EgovBizException("Fieldname is not correct. It must be: " + options.getFieldname());
}
// Generate random name.
String file_extsn = FilenameUtils.getExtension(Utils.getFileName(file)).toLowerCase();
String extension = file_extsn;
extension = (extension != null && extension != "") ? "." + extension : extension;
String name;
try {
name = Utils.generateUniqueString() + extension;
} catch (NoSuchAlgorithmException e) {
// return null;
throw new EgovBizException("NoSuchAlgorithmException!");
}
String fullPath = fileRoute + name;
InputStream fileContent;
try {
fileContent = file.getInputStream();
} catch (IOException e) {
throw new EgovBizException("IOException!");
}
String absoluteServerPath = getAbsoluteServerPath(req, fullPath);
// String absoluteServerPath = linkName;
java.io.File targetFile = null;
if (absoluteServerPath != null && !absoluteServerPath.equals("")) {
targetFile = new java.io.File(absoluteServerPath);
} else {
return null;
}
// Resize image.
if (options instanceof ImageOptions && ((ImageOptions) options).getResizeOptions() != null) {
ImageOptions.ResizeOptions imageOptions = ((ImageOptions) options).getResizeOptions();
Builder extends InputStream> thumbnailsBuilder = Thumbnails.of(fileContent);
// Check aspect ratio.
int newWidth = imageOptions.getNewWidth();
int newHeight = imageOptions.getNewHeight();
if (imageOptions.getKeepAspectRatio()) {
thumbnailsBuilder = thumbnailsBuilder.size(newWidth, newHeight);
} else {
thumbnailsBuilder = thumbnailsBuilder.forceSize(newWidth, newHeight);
}
try {
thumbnailsBuilder.toFile(targetFile);
} catch (IOException e) {
LOGGER.error(e.getCause().getMessage());
}
} else {
try {
FileUtils.copyInputStreamToFile(fileContent, targetFile);
} catch (IOException e) {
LOGGER.error(e.getCause().getMessage());
}
}
if (options.getValidation() != null
&& !options.getValidation().check(absoluteServerPath, file.getContentType())) {
delete(req, fullPath);
throw new EgovBizException("File does not meet the validation.");
}
// 정보 셋팅
EditorFileVO fileVO = new EditorFileVO();
fileVO.setLink(options.getDownloadUrl());
fileVO.setFullPath(fullPath);
fileVO.setFileExtsn(file_extsn);
fileVO.setOriginFileNm(file.getOriginalFilename());
fileVO.setSysFileNm(name);
fileVO.setUploadDir(fileRoute);
fileVO.setFileSize(file.getSize());
fileVO.setMime(file.getContentType());
return fileVO;
}
/**
* Get absolute server path.
*
* @param req
* Used to get the servlet context.
* @param relativePath
* Relative path.
* @return Absolute path.
*/
public static String getAbsoluteServerPath(HttpServletRequest req, String relativePath) {
// return req.getServletContext().getRealPath(relativePath);
return relativePath;
}
/**
* Delete a file from disk.
*
* @param req
* Used to get the servlet context.
* @param src
* Server file path.
*/
public static void delete(HttpServletRequest req, String src) {
String filePath = getAbsoluteServerPath(req, src);
java.io.File file = new java.io.File(filePath);
if (file.exists()) {
file.delete();
}
}
/**
* 압축파일(zip) 파일 업로드 - 압축해제 후 저장
* @param req
* @param fileRoute
* @param options
* @return
* @throws EgovBizException
* @throws NoSuchAlgorithmException
*/
public static List zipUpload(HttpServletRequest req, String fileRoute, FileOptions options)
throws EgovBizException, NoSuchAlgorithmException {
if (options == null) {
options = defaultOptions;
}
if (req.getContentType() == null || req.getContentType().toLowerCase().indexOf(multipartContentType) == -1) {
throw new EgovBizException("Invalid contentType. It must be " + multipartContentType);
}
MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) req;
MultipartFile file = multipartHttpServletRequest.getFile(options.getFieldname());
if (file == null) {
throw new EgovBizException("Fieldname is not correct. It must be: " + options.getFieldname());
}
List fileMap = new ArrayList<>();
ZipArchiveInputStream zin = null;
ZipArchiveEntry entry = null;
try {
zin = new ZipArchiveInputStream(file.getInputStream(), "EUC-KR", false);
java.io.File dir = new java.io.File(fileRoute);
dir.setExecutable(true);
dir.setReadable(true);
dir.setWritable(true);
if (!dir.exists()) {
boolean result = false;
try{
dir.mkdirs();
result = true;
}
catch(SecurityException se){
LOGGER.error("fail to process create Dir {}", se);
}
if(result) {
LOGGER.info("Dir created");
}
}
try {
while ((entry = zin.getNextZipEntry()) != null) {
// Generate random name.
String file_extsn = FilenameUtils.getExtension(entry.getName());
String extension = file_extsn;
extension = (extension != null && extension != "") ? "." + extension : extension;
String sysFileNm = Utils.generateUniqueString() + extension;
String fullPath = fileRoute + sysFileNm;
Path source = Paths.get(fullPath);
OutputStream zout = null;
try {
zout = new FileOutputStream(source.toFile());
//버퍼
byte[] buf = new byte[1024];
int len;
while ((len = zin.read(buf)) > 0) {
zout.write(buf, 0, len);
}
// 정보 셋팅
EditorFileVO fileVO = new EditorFileVO();
fileVO.setLink(options.getDownloadUrl());
fileVO.setFullPath(fullPath);
fileVO.setFileExtsn(file_extsn);
fileVO.setOriginFileNm(entry.getName());
fileVO.setSysFileNm(sysFileNm);
fileVO.setUploadDir(fileRoute);
fileVO.setFileSize(entry.getSize());
fileVO.setMime(Files.probeContentType(source));
fileMap.add(fileVO);
} catch (IOException e) {
LOGGER.error("fail to process zipUpload File {}", e);
} finally {
EgovResourceCloseHelper.close(zout);
}
}
} catch (IOException e) {
LOGGER.error("fail to process zipUpload File {}", e);
} finally {
EgovResourceCloseHelper.close(zin);
}
} catch (IOException e) {
LOGGER.error("fail to process zipUpload File {}", e);
}
return fileMap;
}
/**
* 디렉토리 하위파일 및 디렉토리 삭제
* @param path
*/
public static void deleteDirFileFn(String path) {
java.io.File file = new java.io.File(path); // 매개변수로 받은 경로를 파일객체선언 (/home/nation909/test 경로의 폴더를 지정함)
java.io.File[] files = file.listFiles(); // 해당 폴더 안의 파일들을 files 변수에 담음
if(files.length > 0) { // 파일, 폴더가 1개라도 있을경우 실행
for (int i=0; i 0){
outStream.write(buffer, 0, length);
}
vo = new EditorFileVO();
vo.setLink(options.getDownloadUrl());
vo.setFullPath(copyFullPath);
vo.setFileExtsn(tempFile.getFileExtsn());
vo.setOriginFileNm(tempFile.getOriginFileNm());
vo.setSysFileNm(tempFile.getSysFileNm());
vo.setUploadDir(copyPath);
vo.setFileSize(tempFile.getFileSize());
vo.setMime(tempFile.getMime());
} catch(IOException e) {
LOGGER.error("fail to process fileCopy {}", e);
} finally {
EgovResourceCloseHelper.close(inStream, outStream);
}
return vo;
}
/**
* List 파일객체를 받아 다수의 파일을 압축파일로 압축 후 다운로드
* @param req
* - HttpServletRequest
* @param res
* - HttpServletResponse
* @param fileList
* - 파일 정보를 담은 객체
* @param fileRoute
* - 파일을 저장할 경로
* @throws EgovBizException
*/
public static void zipDown(HttpServletRequest req
, HttpServletResponse res
, List fileList
, String fileRoute) throws EgovBizException {
//추가 temp 경로 생성
String zipFilePath = Utils.getAddTempRoute(fileRoute);
// 파일명 생성 시 날짜
Calendar cal = Calendar.getInstance();
//현재 년도, 월, 일
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH) + 1;
int date = cal.get(Calendar.DATE);
String downloadFileName = year + "_" + month + "_" + date;
String zipFileNm = downloadFileName + ".zip";
String fullPath = zipFilePath + zipFileNm;
java.io.File file = new java.io.File(fullPath);
try {
//디렉토리 가져오기
java.io.File dir = new java.io.File(zipFilePath);
dir.setExecutable(true);
dir.setReadable(true);
dir.setWritable(true);
if (!dir.exists()) {
boolean result = false;
try{
dir.mkdirs();
result = true;
}
catch(SecurityException se){
LOGGER.error("fail to process create Dir {}", se);
}
if(result) {
LOGGER.info("Dir created");
}
}
// ZipOutputStream을 FileOutputStream 으로 감쌈
FileOutputStream fout = null;
ZipArchiveOutputStream zout = null;
FileInputStream fin = null;
try {
fout = new FileOutputStream(file);
zout = new ZipArchiveOutputStream(fout);
for (EditorFileVO vo : fileList) {
try {
//본래 파일명 유지
ZipArchiveEntry zipEntry = new ZipArchiveEntry(vo.getOriginFileNm());
zout.putArchiveEntry(zipEntry);
//경로포함 압축
//zout.putNextEntry(new ZipEntry(sourceFiles.get(i)));
java.io.File voFile = new java.io.File(vo.getFullPath());
fin = new FileInputStream(voFile);
byte[] buf = new byte[1024];
int len;
// input file을 1024바이트로 읽음, zip stream에 읽은 바이트를 씀
while((len = fin.read(buf)) > 0) {
zout.write(buf, 0, len);
}
} catch (IOException e) {
LOGGER.error("fail to process zipDown file {}", e);
// throw new Exception(e.getMessage());
} finally {
EgovResourceCloseHelper.close(fin, zout);
}
}
} catch (IOException e) {
LOGGER.error("fail to process zipDown file {}", e);
} finally {
EgovResourceCloseHelper.close(zout);
}
String userAgent = req.getHeader("User-Agent");
String conVstr = null;
if (userAgent.contains("MSIE")) {
conVstr = URLEncoder.encode(zipFileNm,"UTF-8");
} else if (userAgent.contains("Trident")) {
conVstr = URLEncoder.encode(zipFileNm,"UTF-8");
} else if(userAgent.contains("Chrome")) {
conVstr = new String(zipFileNm.getBytes("UTF-8"), "ISO-8859-1");
} else if(userAgent.contains("Opera")) {
conVstr = new String(zipFileNm.getBytes("UTF-8"), "ISO-8859-1");
} else if (userAgent.contains("Mozilla")){
conVstr = new String(zipFileNm.getBytes("UTF-8"), "ISO-8859-1");
} else {
conVstr = new String(zipFileNm.getBytes("UTF-8"), "ISO-8859-1");
}
res.setHeader("Content-Disposition", "attachment; fileName=\"" + conVstr + "\";");
res.setContentType("application/octet-stream;charset=UTF-8");
res.setHeader("Content-Transfer-Encoding", "binary");
FileInputStream fis = null;
BufferedInputStream bis = null;
ServletOutputStream so = null;
BufferedOutputStream bos = null;
try {
fis = new FileInputStream(file);
bis = new BufferedInputStream(fis);
so = res.getOutputStream();
bos = new BufferedOutputStream(so);
byte[] data = new byte[2048];
int input=0;
while((input=bis.read(data))!=-1){
bos.write(data,0,input);
bos.flush();
}
} catch (IOException e) {
LOGGER.error("fail to process zipDown file {}", e);
} finally {
EgovResourceCloseHelper.close(fis, bis, so, bos);
}
} catch (IOException e) {
LOGGER.error("fail to process zipDown file {}", e);
} finally {
File.deleteDirFileFn(zipFilePath);
}
}
}