[JAVA + AXIOS] 엑셀 파일 생성 후 ZipOutputStream를 사용하여 압축(zip) 하여 다운로드 하는 방법
데이터베이스에서 데이터를 조회 후 JAVA 서버사이드에서 엑셀파일을 생성 후 ZIP 파일에 추가하여 압축 후 압축파일을 다운로는 해야하는 경우가 있다.
이때 엑셀파일을 서버 어딘가에 임시로 생성해서 ZIP파일에 추가하는 방법도 있겠지만 이렇게 처리하는 경우 작업 후 임시파일을 삭제 처리해주면 되는 방법도 있다. 이번에 알아볼 방법은 생성한 엑셀 파일을 메모리에 가지고 있다가 ZIP파일에 바로 추가하는 방법에 대한 예제이다.
[vue.js 프론트엔드에서 axios 호출하는 스크립트]
fnDown(){
const params = {
userId: 1212,
};
this.axiosDownloadExcelZip(params, fileName);
},
axiosDownloadExcelZip(params, fileName) {
const p = params;
p.fileName = fileName;
axios({
method: 'POST',
url: '/com/download/ExcelToZip.do',
responseType: 'blob', // important
headers: {
'X-Requested-Type': 'XHR',
},
data: new URLSearchParams(p),
}).then((response) => {
console.log(response);
const url = window.URL.createObjectURL(new Blob([response.data], { type: response.headers['content-type'] })); // {type:'application/zip'}
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', `${fileName}.zip`);
document.body.appendChild(link);
link.click();
link.remove();
}).catch((err) => {
throw new Error(err.message);
}
}).finally(() => {
});
},
[Controller]
@RequestMapping(value = { "/com/download/ExcelToZip.do", "/ExcelToZip.do" })
public FileZipService excelToZip(HttpServletRequest request, ModelMap model) throws Exception
{
ArrayList<사용자 정의> result = db 조회 프로세서 호출;
model.addAttribute("EXCEL_DATA", result);
model.put("generalDAO", generalDAO);
model.put("USER_ID", request.getParameter("userId"));
return new FileZipService();
}
[Service]
public class FileZipService extends AbstractView
{
protected Logger log = LoggerFactory.getLogger(this.getClass());
@SuppressWarnings("unchecked")
@Override
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest req, HttpServletResponse res) throws Exception
{
List<사용자 정의 Object> list;
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ZipOutputStream zipStream = new ZipOutputStream(byteOut);
try {
List<사용자 정의 Object> result = null;
// 엑셀파일 생성 후 zip 파일에 추가
makeZip(model , zipStream);
//파일정보 리스트(db에서 조회해온 리스트이다.)
// 추가적인 여러개의 파일들에 대한 zip 파일에 추가가 필요한 경우
if (list != null && list.size() > 0)
{
result = (List<사용자 정의 Object>) list.get(0);
try {
for(int intIndex = 0; intIndex < result.size(); intIndex++)
{
String filePath = uploadDir + result.get(intIndex).get("FILE_PATH").toString();
FileInputStream inputStream = null;
if (filePath == null || filePath.equals("")) {
return;
}
// 작업전 파일 존재여부 먼저 체크
File file = new File(filePath);
if (file.exists()) {
inputStream = new FileInputStream(filePath);
ZipEntry entry = new ZipEntry(result.get(intIndex).get("FILE_NAME").toString());
zipStream.putNextEntry(entry);
int intLen;
byte[] buf = new byte[4096];
while((intLen = inputStream.read(buf)) > 0)
{
zipStream.write(buf, 0, intLen);
}
zipStream.closeEntry();
inputStream.close();
}
}
}
catch(Exception ex)
{
ex.printStackTrace();
log.info("파일 압축 작업 진행 시 에러 발생");
}
finally {
list = null;
}
}
zipStream.finish();
res.setContentType("application/zip");
res.setHeader("Content-Disposition", "attachment; filename=""+tempFileName+".zip"+"";");
res.getOutputStream().write(byteOut.toByteArray());
res.flushBuffer();
zipStream.flush();
zipStream.close();
byteOut.close();
}catch(Exception ex) {
ex.printStackTrace();
log.info(ex.toString());
log.info(ex.getMessage());
} finally {
zipStream.flush();
zipStream.close();
byteOut.close();
}
}
private void makeZip(Map<String, Object> model, ZipOutputStream zipStream) throws IOException
{
SXSSFWorkbook wb = new SXSSFWorkbook(500);
wb.setCompressTempFiles(true);
try
{
//DB조회한 데이터에 대한 엑셀 데이터 생성은 생략............
ZipEntry zipEntry = new ZipEntry("myExcel.xlsx" );
zipStream.putNextEntry(zipEntry);
wb.write(new NonCloseableOutputStream(zipStream));
zipStream.closeEntry();
}
catch (Exception e)
{
log.error("Excel Download Error", e);
}
finally
{
wb.dispose();
}
}
}
[아래 코드는 바로 zip 다운하는 케이스]
private void ZipDownload(HttpServletRequest req, HttpServletResponse res, String strUploadDir)
{
byte[] buf = new byte[4096];
Date dtNow = new Date(System.currentTimeMillis());
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
String strNow = sdf.format(dtNow);
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ZipOutputStream zipOut = new ZipOutputStream(byteOut); //new ZipOutputStream(new FileOutputStream(strUploadDir + File.separator + strNow + ".zip"));
try
{
for(int intIndex = 0; intIndex < map.size(); intIndex++)
{
String filePath = strUploadDir + File.separator + map.get(intIndex).get("file_path").toString();
FileInputStream fileIn = new FileInputStream(filePath);
ZipEntry entry = new ZipEntry(map.get(intIndex).get("file_name").toString());
zipOut.putNextEntry(entry);
int intLen;
while((intLen = fileIn.read(buf)) > 0)
{
zipOut.write(buf, 0, intLen);
}
zipOut.closeEntry();
fileIn.close();
}
zipOut.finish();
res.setContentType("application/zip");
res.setHeader("Content-Disposition", "attachment; filename=""+strNow+".zip"+"";");
res.getOutputStream().write(byteOut.toByteArray());
res.flushBuffer();
zipOut.flush();
zipOut.close();
byteOut.close();
}
catch(Exception ex)
{
ex.printStackTrace();
log.info(ex.toString());
log.info(ex.getMessage());
} finally {
}
}
[REFERENCE]
- https://www.tabnine.com/code/java/methods/java.util.zip.ZipOutputStream/write
- https://stackoverflow.com/questions/17928045/zipping-inputstream-returning-inputstream-in-memory-no-file
- https://stackoverflow.com/questions/1091788/how-to-create-a-zip-file-in-java/1091817#1091817