You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
VIPS/src/main/java/egovframework/util/excel/SxssfExcelFile.java

189 lines
7.7 KiB
Java

package egovframework.util.excel;
import org.checkerframework.checker.nullness.qual.Nullable;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
/**
*
*
* <p> {@link BaseSxssfExcelFile} .
* HTTP , OutputStream .</p>
*
* <p><b> 1: HTTP </b></p>
* <pre>{@code
* @GetMapping("/download.xlsx")
* public void downloadExcel(HttpServletRequest request, HttpServletResponse response) {
* List<UserVO> dataList = userService.selectUserList();
* ExcelSheetData sheetData = ExcelSheetData.of(dataList, UserVO.class, "사용자 목록");
* new SxssfExcelFile(sheetData, request, response, "사용자목록.xlsx");
* }
* }</pre>
*
* <p><b> 2: </b></p>
* <pre>{@code
* @GetMapping("/download-encrypted.xlsx")
* public void downloadEncryptedExcel(HttpServletRequest request, HttpServletResponse response) {
* List<UserVO> dataList = userService.selectUserList();
* ExcelSheetData sheetData = ExcelSheetData.of(dataList, UserVO.class, "사용자 목록");
* new SxssfExcelFile(sheetData, request, response, "사용자목록.xlsx", "password123");
* }
* }</pre>
*
* <p><b> 3: OutputStream </b></p>
* <pre>{@code
* try (FileOutputStream fos = new FileOutputStream("output.xlsx")) {
* List<UserVO> dataList = userService.selectUserList();
* ExcelSheetData sheetData = ExcelSheetData.of(dataList, UserVO.class);
* new SxssfExcelFile(sheetData, fos, null);
* }
* }</pre>
*
* <p><b>VO :</b></p>
* <pre>{@code
* @ExcelSheet(name = "사용자")
* public class UserVO {
* @ExcelColumn(headerName = "이름", headerWidth = 20)
* private String userName;
*
* @ExcelColumn(headerName = "이메일", headerWidth = 30)
* private String email;
*
* @ExcelColumn(headerName = "전화번호")
* private String phone;
* }
* }</pre>
*
* @see BaseSxssfExcelFile
* @see ExcelSheetData
* @see ExcelColumn
* @author eGovFrame
*/
public class SxssfExcelFile extends BaseSxssfExcelFile {
// ==================== 생성자 (HTTP 응답 다운로드) ====================
/**
* HTTP ( ).
*
* <p> HTTP .
* .</p>
*
* @param data ( , , )
* @param request HTTP ( )
* @param response HTTP
* @param fileName ( , : "사용자목록.xlsx")
* @throws RuntimeException
*/
public SxssfExcelFile(ExcelSheetData data, HttpServletRequest request, HttpServletResponse response,
String fileName) {
this(data, request, response, fileName, null);
}
/**
* HTTP ( ).
*
* <p> HTTP .
* .</p>
*
* @param data ( , , )
* @param request HTTP ( )
* @param response HTTP
* @param fileName ( , : "사용자목록.xlsx")
* @param password (null )
* @throws RuntimeException
*/
public SxssfExcelFile(ExcelSheetData data, HttpServletRequest request, HttpServletResponse response,
String fileName, @Nullable String password) {
try {
setDownloadHeaders(request, response, fileName);
ExcelMetadata metadata = ExcelMetadataFactory.getInstance().createMetadata(data.getType());
renderSheetContent(data, metadata);
writeWithEncryption(response.getOutputStream(), password);
} catch (IOException e) {
throw new RuntimeException("HTTP 응답으로 엑셀 파일 출력 중 오류가 발생했습니다.", e);
}
}
// ==================== 생성자 (OutputStream 출력) ====================
/**
* OutputStream .
*
* <p> OutputStream .
* .</p>
*
* @param data ( , , )
* @param outputStream
* @param password (null )
* @throws RuntimeException
*/
public SxssfExcelFile(ExcelSheetData data, OutputStream outputStream, @Nullable String password) {
ExcelMetadata metadata = ExcelMetadataFactory.getInstance().createMetadata(data.getType());
renderSheetContent(data, metadata);
writeWithEncryption(outputStream, password);
}
// ==================== private 헬퍼 메서드 ====================
/**
* HTTP .
*
* <p> Content-Disposition :
* <ul>
* <li>IE (MSIE/Trident): UTF-8 URL (+ )</li>
* <li> : UTF-8 ISO-8859-1 </li>
* </ul>
* </p>
*
* @param request HTTP (User-Agent )
* @param response HTTP
* @param fileName
* @throws RuntimeException
*/
private void setDownloadHeaders(HttpServletRequest request, HttpServletResponse response, String fileName) {
try {
String browser = request.getHeader("User-Agent");
String encodedFileName = encodeFileName(fileName, browser);
response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("파일명 인코딩 중 오류가 발생했습니다.", e);
}
}
/**
* .
*
* @param fileName
* @param userAgent User-Agent
* @return
* @throws UnsupportedEncodingException
*/
private String encodeFileName(String fileName, String userAgent) throws UnsupportedEncodingException {
if (isInternetExplorer(userAgent)) {
// IE: UTF-8 URL 인코딩 (+ -> 공백 처리)
return URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
} else {
// Chrome, Firefox 등: UTF-8 바이트를 ISO-8859-1로 변환
return new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
}
}
/**
* User-Agent Internet Explorer .
*
* @param userAgent User-Agent
* @return IE true, false
*/
private boolean isInternetExplorer(String userAgent) {
return userAgent != null && (userAgent.contains("MSIE") || userAgent.contains("Trident"));
}
}