-
SpringBoot에서 엑셀파일 암호화 후 내려받기Language/Java 2024. 6. 18. 17:30
개인정보가 들어간 엑셀 파일을 다운로드 하게 되면 보안 이슈가 발생 할수도 있으니 급하게 엑셀 다운로드 파일에 암호를 넣고 릴리즈 후 기록해 둔다.
TestController
@Tag(name = "test") @AppController(path = "/v1") @RequiredArgsConstructor public class TestController extends BaseController { ... @Operation(summary = "어쩌구 저쩌구 엑셀 다운로드", description = "") @GetMapping(value = "/tests/{testId}/comments/export") public ResponseEntity<byte[]> export(@PathVariable("testId") String testId, JsonNode jsonNode, HttpServletResponse response, ...) throws Exception { ... byte[] bytes = testService.getCommentListExcel(params); // CORS 헤더 허용 (React에서 파일명 받아야 하니깐 추가) response.addHeader("Access-Control-Expose-Headers", "Content-Disposition"); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")); headers.setContentLength(bytes.length); headers.setContentDispositionFormData("attachment", URLEncoder.encode("콘텐츠_댓글_사용자목록.xlsx", "UTF-8")); return new ResponseEntity<>(bytes, headers, HttpStatus.OK); } ... }
TestService
@Service @RequiredArgsConstructor public class TestService extends BaseService { ... public byte[] getCommentListExcel(Map<String, Object> params) throws Exception { String password = Utils.makeNumEngRandomString(6); List<Map<String, String>> data = commentDao.getCommentList(params); Header header = new Header(); header.addColumn(new Column("ROW_NUM", "순서", 200, Style.ColumnAlign.CENTER)); header.addColumn(new Column("NICKNAME", "닉네임", 400, Style.ColumnAlign.CENTER)); ... header.addColumn(new Column("CONTENT", "내용", 700, Style.ColumnAlign.LEFT)); List<String[]> items = this.getCommentListExcelItems(header, data); byte[] excelBytes = ExcelUtil.getEncryptedExcelBytes(header, items, password); // SNS 발송 StringBuilder sb = new StringBuilder(); sb.append("[댓글작성 회원목록]\n"); sb.append(String.format("비밀번호 : %s\n", password)); PurplebookBase.sendMessage(params.get("hpNo").toString(), sb.toString()); return excelBytes; } public static List<String[]> getCommentListExcelItems(Header header, List<Map<String, String>> list) throws Exception { List<String[]> items = new ArrayList<>(); for (int rowIndex = 0; rowIndex < list.size(); rowIndex++) { Map<String, String> rowData = list.get(rowIndex); String[] row = new String[header.getColumns().size()]; for (int columnIndex = 0; columnIndex < header.getColumns().size(); columnIndex++) { Column column = header.getColumns().get(columnIndex); String value = rowData.get(column.getId()); if (column.getId().equals("ROW_NUM") == true) { row[columnIndex] = String.valueOf(rowIndex + 1); ... ... } else if (column.getId().equals("REG_DT") == true || column.getId().equals("MOD_DT") == true) { row[columnIndex] = DateUtils.getDate(DateUtils.getDateFromStringFormat("yyyy-MM-dd HH:mm:ss", value), "yyyy-MM-dd HH:mm"); } else { row[columnIndex] = value; } } items.add(row); } return items; } ... }
ExcelUtils
package net.neoflat.common.core.util; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; import net.neoflat.common.dto.excel.Column; import net.neoflat.common.dto.excel.Header; import net.neoflat.common.dto.excel.Style; import org.apache.poi.poifs.crypt.EncryptionInfo; import org.apache.poi.poifs.crypt.EncryptionMode; import org.apache.poi.poifs.crypt.Encryptor; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.xssf.usermodel.XSSFRow; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; public class ExcelUtil { ... private static XSSFWorkbook getWorkbook(Header header, List<String[]> items) { XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet(); int rowIndex = 0; XSSFRow row = sheet.createRow(rowIndex++); for (int columnIndex = 0; columnIndex < header.getColumns().size(); columnIndex++) { Column column = header.getColumns().get(columnIndex); // TODO. 열 너비 // sheet.setColumnWidth(0, characterWidth * 256); // 첫 번째 열의 너비 설정 sheet.setColumnWidth(columnIndex, column.getWidth() * 10); Cell cell = row.createCell(columnIndex); cell.setCellValue(column.getTitle()); // TODO. Style 지정 cell.setCellStyle(Style.getHeaderStyle(workbook)); } for (String[] record : items) { row = sheet.createRow(rowIndex++); for (int columnIndex = 0; columnIndex < header.getColumns().size(); columnIndex++) { Column column = header.getColumns().get(columnIndex); Cell cell = row.createCell(columnIndex); String value = record[columnIndex]; if (value != null) { cell.setCellValue(value.toString()); cell.setCellStyle(Style.getCellStyle(workbook, column)); } } } ... return workbook; } /** * 엑셀 기본 * * @param header * @param items * @return * @throws IOException */ public static byte[] getExcelBytes(Header header, List<String[]> items) throws IOException { XSSFWorkbook workbook = getWorkbook(header, items); // Write workbook to ByteArrayOutputStream ByteArrayOutputStream bos = new ByteArrayOutputStream(); workbook.write(bos); workbook.close(); bos.close(); return bos.toByteArray(); } /** * 엑셀 파일 암호화 * * @param header * @param items * @param password * @return * @throws Exception */ public static byte[] getEncryptedExcelBytes(Header header, List<String[]> items, String password) throws Exception { XSSFWorkbook workbook = getWorkbook(header, items); // Create a ByteArrayOutputStream to hold the encrypted Excel file ByteArrayOutputStream bos = new ByteArrayOutputStream(); // Encrypt the workbook and write to the ByteArrayOutputStream POIFSFileSystem fs = new POIFSFileSystem(); EncryptionInfo info = new EncryptionInfo(EncryptionMode.standard); Encryptor encryptor = info.getEncryptor(); encryptor.confirmPassword(password); // Replace with your desired password try (OutputStream os = encryptor.getDataStream(fs)) { workbook.write(os); } workbook.close(); fs.writeFilesystem(bos); bos.close(); return bos.toByteArray(); } ... }
너무 GPT를 믿지 말자. 이놈이 자꾸 훼이크 써써 시간이 더 걸릴때도 많다.
참고)
'Language > Java' 카테고리의 다른 글
비트마스크 적용 (QueryDSL & Hibernate 6.x) (0) 2024.08.28 SpringBoot에서 QueryDSL 설정 및 사용 (0) 2024.08.16 Java Enum 적용 (0) 2024.01.15 문자열 날짜 포멧 변경 (0) 2023.04.18 리엑트 및 Spring 레거시에서 파일 업로드 및 다운로드 (0) 2023.03.18