본문 바로가기

IT/개발

Spring(JAVA) 엑셀 대용량 업로드

Spring으로 개발한다면 대부분은 poi 라이브러리를 사용해서 프로젝트를 진행합니다.
poi 라이브러리는 너무 좋습니다.
엑셀을 파싱해서 데이터를 불러오기 때문입니다.

하지만 데이터의 건수가 많아지면 당연하게도 서버의 메모리의 사용률은 증가됩니다.
그로인해 서비스의 영향을 줄 수 있습니다.

우선 구글링을 통해 얻은 정보를 공유합니다.
로직의 여러 class들이 어떤 기능을 하는지는 추후 추가하도록 하겠습니다.

아래 소스는 실제 엑셀이 파싱되는 부분을 구현한겁니다.(구글링참고)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
public class ExcelSheetHandler implements SheetContentsHandler{
    private int current Col = -1;
    private int currRowNum    =  0;
 
    String filePath            = "";
 
    private List<List<String>> rows = new ArrayList<List<String>>();    //실제 엑셀을 파싱해서 담아지는 데이터
    private List<String>       row    = new ArrayList<String>();
    private List<String>     header    = new ArrayList<String>();
 
    public static ExcelSheetHandler readExcel(File file) throws Exception{
 
        ExcelSheetHandler sheetHandler = new ExcelSheetHandler();
        try{
            
            //org.apache.poi.openxml4j.opc.OPCPackage
            OPCPackage opc            = OPCPackage.open(file);
 
            //org.apache.poi.xssf.eventusermodel.XSSFReader
            XSSFReader xssfReader    = new XSSFReader(opc);
 
            //org.apache.poi.xssf.model.StylesTable
            StylesTable styles        = xssfReader.getStylesTable();
 
            //org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable
            ReadOnlySharedStringsTable strings    = new ReadOnlySharedStringsTable(opc);
            
            //엑셀의 시트를 하나만 가져오기입니다.
            //여러개일경우 while문으로 추출하셔야 됩니다.
            InputStream inputStream    = xssfReader.getSheetsData().next();    
 
            //org.xml.sax.InputSource
            InputSource    inputSource = new InputSource(inputStream);
 
            //org.xml.sax.Contenthandler
            ContentHandler handle    = new XSSFSheetXMLHandler(styles, strings, sheetHandler, false);
    
            XMLReader xmlReader        = SAXHelper.newXMLReader();
            xmlReader.setContentHandler(handle);
 
            xmlReader.parse(inputSource);
            inputStream.close();
            opc.close();
 
        }catch(Exception e){
            //에러 발생했을때 하시고 싶은 TO-DO 
        }
        return sheetHandler
 
    }//readExcel - end
 
    public List<List<String>> getRows(){
        return rows;
    }
 
    @Override
    public void startRow(int arg0){
        this.currentCol = -1;
        this.currRowNum    = arg0;
    }    
 
    @Override
    public void cell(String columnName, String value, XSSFComment var3){
        int iCol = (new CellReference(columnName)).getCol();
        int emptyCol = iCol - currentCol -1;
        
        for(int i=0; i< emptyCol; i++){
            row.add("");
        }
        currentCol = iCol;
        row.add(value);
    }
 
    @Override
    public void headerFooter(String arg0, boolean arg1, String arg2){
        //사용안합니다.
    }
 
    
    @Override
    public void endRow(int rowNum){
        if(rowNum == 0){
            header = new ArrayList(row);
        }
        else{
            if(row.size() < hader.size()){
                for(int i = row.size(); i<header.size(); i++){
                    row.add("");
                }
            }
            rows.add(new ArrayList(row));
        }
        row.clear();
    }
}    
 
cs

 

그럼이제 실제 구현한 class를 호출하는 로직을 만들어 보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 엑셀 데이터 양식 example
/     A열                B열
1행   test@naver.com    Seoul
2행      mouse@gmail.com   Busan
3행   apple@daum.net    Jeju
/
 
 
//해당 파일은 업로드파일
String filePath = "test.xlsx";
 
File file = new File(filePath);
 
ExcelSheetHandler excelSheetHandler = ExcelSheetHandler.readExcel(file);
List<List<String>> excelDatas = excelSheetHandler.getRows();
 
//excelDatas  >>>>>    [[ test@naver.com, Seoul ],[ mouse@gmail.com, Busan ], [ apple@daum.net, Jeju ]]
 
int iCol = 0;    //컬럼 구분값
int iRow = 0;    //행 구분값
 
for(List<String> dataRow : excelDatas){
    for(String str : dataRow){
        if(iCol == 0){
            //test@naver.com
            System.out.println(str);
        }
        else if(iCol == 1){
            //Seoul
            System.out.println(str);
        }
        iCol++;
    }
    iCol = 0;
    iRow = 0;
}
cs

내부 로직들의 class가 어떤 역할을 하는지는 더 조사후에 추가하도록 하겠습니다.

감사합니다.

'IT > 개발' 카테고리의 다른 글

JAVA 입력과 출력 stream  (0) 2019.10.19
Spring ibatis resultMap 쿼리 2개실행  (0) 2019.10.16
스프링 form태그  (0) 2019.10.09
Java 파일 읽기, 파일 쓰기  (0) 2019.10.08
Spring Transactional annotation  (0) 2019.09.27