728x90
반응형
# ExcelReadUtil.java
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.util.XMLHelper;
import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Component;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
@Component
@Slf4j
public class ExcelReadUtil {
private List<HashMap<Object, Object>> distinctArray(List<HashMap<Object, Object>> target) {
if (target != null) {
target = target.stream().filter(distinctByKey(o -> o.get(0))).collect(Collectors.toList());
}
return target;
}
private <T> Predicate<T> distinctByKey(Function<? super T,Object> keyExtractor) {
Map<Object,Boolean> seen = new ConcurrentHashMap<>();
return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
// XSSF and SAX (Event API) 방식으로 읽음
public List<HashMap<Object, Object>> readExcelFileV2(InputStream isr, String from) throws Exception {
List<HashMap<Object, Object>> excelResult = new ArrayList<>();
log.info("XSSF and SAX Excel Reader Start");
long startTime = System.currentTimeMillis();
SheetHandler sheetHandler = new SheetHandler();
OPCPackage pkg = OPCPackage.open(isr);
//메모리를 적게 사용하며 sax 형식을 사용할 수 있게 함
XSSFReader xssfReader = new XSSFReader(pkg);
//파일의 데이터를 Table형식으로 읽을 수 있도록 지원
ReadOnlySharedStringsTable data = new ReadOnlySharedStringsTable(pkg);
//읽어온 Table에 적용되어 있는 Style
StylesTable styles = xssfReader.getStylesTable();
//엑셀의 첫번째 sheet정보만 읽어오기 위해 사용 만약 다중 sheet 처리를 위해서는 반복문 필요
InputStream sheetStream = xssfReader.getSheetsData().next();
InputSource sheetSource = new InputSource(sheetStream);
//XMLHandler 생성
ContentHandler handler = new XSSFSheetXMLHandler(styles, data, sheetHandler, false);
//SAX 형식의 XMLReader 생성
XMLReader sheetParser = XMLHelper.newXMLReader();
//XMLReader에 재정의하여 구현한 인터페이스 설정
sheetParser.setContentHandler(handler);
//파싱하여 처리
sheetParser.parse(sheetSource);
sheetStream.close();
pkg.close();
int listSize = sheetHandler.getRowsMapList().size();
excelResult = distinctArray(sheetHandler.getRowsMapList());
if (StringUtils.equals(from, "valid")) {
HashMap<Object, Object> oldNumberCountMap = new HashMap<>();
oldNumberCountMap.put("oldNumberCount", "" + sheetHandler.getOldNumberCount());
oldNumberCountMap.put("distinctCount", listSize - excelResult.size());
//log.info("oldNumberCountMap : " + oldNumberCountMap);
excelResult.add(oldNumberCountMap);
}
log.info("XSSF and SAX Excel Reader End : " + ((System.currentTimeMillis() - startTime) ) + " millis Second");
return excelResult;
}
}
# MsgSendServiceImpl.java
@Override
public HashMap<String, Object> validExcelFile(MultipartFile file) throws Exception {
JSONObject returnJSON = new JSONObject();
JSONParser parser = new JSONParser();
List<HashMap<Object, Object>> excelMapList = excelReadUtil.readExcelFileV2(file.getInputStream(), "valid");
String oldPhoneNumberCount = "";
int validCount = 0; // 검증 후 발송 시도 건수
log.info("excelMapList.size(): [" + excelMapList.size() + "]");
if (excelMapList.size() > 0) {
oldPhoneNumberCount = (String) (excelMapList.get(excelMapList.size() - 1)).get("oldNumberCount");
excelMapList.remove(excelMapList.size() - 1);
}
String phoneNumberRegulaExpress = "^010(\\d{7,8})";
String phoneNumberRegulaExpress2 = "^050(\\d{8,9})";
String isValid = "true";
String invalidRowNumber = "";
String invalidColumnName = "";
int invalidColumnIdx = 0;
// 엑셀 파일 업로드 10만건 제한
int calcListSize = excelMapList.size() - 1; // 엑셀 파일 읽어올때 첫번째 항목도 읽어 오므로 -1 처리
if (calcListSize > sendLimitCnt) {
returnJSON.put("status", "EXCEL_ROW_COUNT_ERROR");
return returnJSON;
}
// 휴대폰 번호 Validation 체크
for (int i = 1; i < excelMapList.size(); i++) {
HashMap<Object, Object> row = excelMapList.get(i);
/*
if (row.get(0) == null || StringUtils.isEmpty(((String) row.get(0)))) {
continue;
}
*/
String phoneNumber = (String) row.get(0);
if (!(phoneNumber.matches(phoneNumberRegulaExpress) || phoneNumber.matches(phoneNumberRegulaExpress2))) {
log.info("INVALID PHONE NUMBER : " + phoneNumber);
isValid = "phoneNumFalse";
invalidRowNumber = phoneNumber + ",\n";
} else {
validCount += 1;
}
}
// 변수 Null 체크
for(int i = 1; i < 10; i++) {
HashMap<Object, Object> col = excelMapList.get(0);
if(col.get(i) == null) {
break;
} else {
for (int j = 1; j < excelMapList.size(); j++) {
String col_variable = (String) excelMapList.get(j).get(i);
if(col_variable.equals("") || col_variable.equals(null)) {
log.info("INVALID COL VARIABLE : " + col.get(i));
isValid = "colVariableFalse";
invalidColumnName = (String) col.get(i);
invalidColumnIdx = j + 1;
break;
}
}
}
}
if (isValid.equals("true")) {
returnJSON.put("status", "SUCCESS");
returnJSON.put("oldNumberCount", oldPhoneNumberCount);
returnJSON.put("validCount", validCount);
} else if(isValid.equals("phoneNumFalse")) {
invalidRowNumber = invalidRowNumber.substring(0, invalidRowNumber.length() - 2);
returnJSON.put("status", "FAIL_INVALID_PHONE_NUMBER");
returnJSON.put("invalidRow", invalidRowNumber);
} else if(isValid.equals("colVariableFalse")) {
returnJSON.put("status", "FAIL_INVALID_COL_VARIABLE");
returnJSON.put("invalidColumnName", invalidColumnName);
returnJSON.put("invalidColumnIdx", invalidColumnIdx);
}
return returnJSON;
}
# MsgSendController.java
@RequestMapping("/validExcelFile.do")
public HashMap<String, Object> msgSendValidExcelFile(@RequestParam("file") MultipartFile file) throws Exception {
return msgSendService.validExcelFile(file);
}
function validExcelFile() {
$('#loading').show();
var formData = new FormData();
formData.append("file", $("input[name='file_excel']")[0].files[0]);
$.ajax({
url : '/msgSend/validExcelFile.do',
method: 'post',
enctype: 'multipart/form-data',
data : formData,
dataType : 'json',
processData: false,
contentType: false,
success : function(data) {
//console.log(data)
$('#loading').hide();
if (data.status == "SUCCESS") {
if( 0 < data.validCount ) {
var obj = JSON.parse(Base64.decode($("input[name=obj]").val()));
//console.log("msg_send_step1 > validExcelFile > sendPossibleCnt: [" + obj.sendPossibleCnt + "]");
// 발송 가능 건수 와 실제 발송 하려는 건수 비교
if( isNull( obj.sendPossibleCnt ) || obj.sendPossibleCnt >= data.validCount ) {
alert('수신번호 검증이 완료되었습니다.\n\n01X 번호 ' + data.oldNumberCount + '건이 제거되었습니다.');
return;
} else {
alert('발송건수가 초과 되었습니다. 확인 후 다시 첨부 바랍니다.\n발송 시도 건수: [' + addCommas( data.validCount ) + ']\n발송 가능 건수: [' + addCommas( obj.sendPossibleCnt )+ ']');
page_reload();
return;
}
}
}else if (data.status == "FAIL_INVALID_PHONE_NUMBER") {
alert('엑셀파일에서 \n' + data.invalidRow + '\n전화번호 오류가 있습니다.');
page_reload();
return;
}else if (data.status == "FAIL_INVALID_COL_VARIABLE") {
alert('엑셀파일 ' + data.invalidColumnName + '변수 [' + data.invalidColumnIdx + ']열에 변수 값이 없어서 등록이 실패되었습니다.');
page_reload();
return;
}else if(data.status == "EXCEL_ROW_COUNT_ERROR") {
alert("엑셀파일 등록은 30만건을 초과할 수 없습니다.");
page_reload();
return;
}else if (data.status == "FREE_TEMPLATE_VAR_ERROR") {
alert("템플릿 변수가 일치하지 않습니다.\n엑셀파일 변수와 프리 템플릿 변수를 확인해 주세요.")
page_reload();
return;
}else{
alert('수신번호 검증이 실패하였습니다.\n관리자에게 문의하십시오.');
return;
}
},
error: function(xhr, status, error) {
$('#loading').hide();
alert('수신번호 검증이 실패하였습니다.\n관리자에게 문의하십시오.');
}
});
}
728x90
반응형
'IT > WEB' 카테고리의 다른 글
[JAVA] java.sql.SQLException: ORA-01006: 바인드 변수가 없습니다 (0) | 2021.10.29 |
---|---|
[Java] static 변수와 static 메소드 대강 정리 (0) | 2021.10.24 |
[JS] 제이쿼리 선택자에 변수 넣기 (0) | 2021.10.14 |
[JAVA] 스케줄러(Quartz) 실행하는 법 (0) | 2021.10.13 |
[JAVA] Properties 클래스 (0) | 2021.04.19 |