Spring-JSP

[Spring-JSP] 엄청쉬운Poi Excel 업로드 기능 구현

Jeong Jeon
반응형

엑셀 업로드 기능을 만들어보려고 한다.

하나하나 만들어놓고 나중에 편하게 꺼내서 사용하자...!

 

여기저기 블로그 및 사수분께 감사하며...! Begin~

 

1). 엑셀업로드 관련 라이브러리 POI 추가 <pom.xml>

<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi</artifactId>
	<version>3.16</version>
</dependency>
<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi-ooxml</artifactId>
	<version>3.16</version>
</dependency>

 

2). 엑셀 유틸 모듈 작성 <ExcelUtil.java>

한군데에 몰아놓고 꺼내쓰기 좋다.

 

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.imageio.ImageIO;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class ExcelUtil {

	/**
	 * 엑셀파일을 읽어서 Workbook 객체를 리턴한다.
	 * XLS와 XLSX 확장자를 비교한다.
	 * @param filePath
	 * @return
	 */
	public static Workbook getWorkbook(String filePath) {

		/*
         * FileInputStream은 파일의 경로에 있는 파일을
         * 읽어서 Byte로 가져온다.
         *
         * 파일이 존재하지 않는다면은
         * RuntimeException이 발생된다.
         */
		FileInputStream fis = null;
		try {
			fis = new FileInputStream(filePath);
		}catch(FileNotFoundException e) {
			throw new RuntimeException(e.getMessage(), e);
		}

		Workbook workbook = null;

		/*
         * 파일의 확장자를 체크해서 .XLS 라면 HSSFWorkbook에
         * .XLSX라면 XSSFWorkbook에 각각 초기화 한다.
         */
		if(filePath.toUpperCase().endsWith(".XLS")) {
			try {
				workbook = new HSSFWorkbook(fis);
			}catch (IOException  e) {
				throw new RuntimeException(e.getMessage(), e);
			}
		}else if(filePath.toUpperCase().endsWith(".XLSX")) {
			try {
				workbook = new XSSFWorkbook(fis);
			}catch (IOException e) {
				throw new RuntimeException(e.getMessage(), e);
			}
		}

		return workbook;
	}

	/**
     * Cell에 해당하는 Column Name을 가젼온다(A,B,C..)
     * 만약 Cell이 Null이라면 int cellIndex의 값으로
     * Column Name을 가져온다.
     * @param cell
     * @param cellIndex
     * @return
     */
    public static String getName(Cell cell, int cellIndex) {
        int cellNum = 0;
        if(cell != null) {
            cellNum = cell.getColumnIndex();
        }
        else {
            cellNum = cellIndex;
        }

        return CellReference.convertNumToColString(cellNum);
    }


    public static String getValue(Cell cell) {
        String value = "";

		if(cell == null) {
		    value = "";
		}else {
			switch(cell.getCellType()) {
				case Cell.CELL_TYPE_FORMULA :
					value = cell.getCellFormula();
					break;
				case Cell.CELL_TYPE_NUMERIC :
					value = (int)cell.getNumericCellValue() + "";	//(int)형변환 미변환시 소수점 발생가능
					break;
				case Cell.CELL_TYPE_STRING :
					value = cell.getStringCellValue();
					break;
				case Cell.CELL_TYPE_BOOLEAN :
					value = cell.getBooleanCellValue() + "";
					break;
				case Cell.CELL_TYPE_ERROR :
					value = cell.getErrorCellValue() + "";
					break;
				case Cell.CELL_TYPE_BLANK :
					value = "";
					break;
				default :
					value = cell.getStringCellValue();
			}

		}
		return value;
    }

    /**
     * 엑셀파일 내용 읽어오기
     * Service에서 이 함수 호출
     * @param excelReadOption
     * @return
     */
    public static List<Map<String, String>> excelRead(ExcelReadOption excelReadOption) {
    	//엑셀 파일 자체
    	//엑셀파일을 읽어 들인다.
		//FileType.getWorkbook() <-- 파일의 확장자에 따라서 적절하게 가져온다.
    	Workbook wb = getWorkbook(excelReadOption.getFilePath());
    	/**
    	 * 엑셀 파일에서 첫번째 시트를 가지고 온다.
    	 */
    	Sheet sheet = wb.getSheetAt(0);

//    	System.out.println("Sheet 이름: "+ wb.getSheetName(0));
//    	System.out.println("데이터가 있는 Sheet의 수 :" + wb.getNumberOfSheets());
    	/**
    	 * sheet에서 유효한(데이터가 있는) 행의 개수를 가져온다.
    	 */
    	int numOfRows = sheet.getPhysicalNumberOfRows();
    	int numOfCells = 0;

    	Row row = null;
    	Cell cell = null;

    	String cellName = "";
    	/**
    	 * 각 row마다의 값을 저장할 맵 객체
    	 * 저장되는 형식은 다음과 같다.
    	 * put("A", "이름");
    	 * put("B", "게임명");
    	 */
    	Map<String, String> map = null;
    	/*
    	 * 각 Row를 리스트에 담는다.
    	 * 하나의 Row를 하나의 Map으로 표현되며
    	 * List에는 모든 Row가 포함될 것이다.
    	 */
    	List<Map<String, String>> result = new ArrayList<Map<String, String>>();
    	/**
    	 * 각 Row만큼 반복을 한다.
    	 */
    	for(int rowIndex = excelReadOption.getStartRow() - 1; rowIndex < numOfRows; rowIndex++) {
    		/*
    		 * 워크북에서 가져온 시트에서 rowIndex에 해당하는 Row를 가져온다.
    		 * 하나의 Row는 여러개의 Cell을 가진다.
    		 */
			row = sheet.getRow(rowIndex);

			if(row != null) {
				//가져온 Row의 Cell의 개수를 구한다.
				//한개의 행마다 몇개의 cell이 있는지 리턴
				//numOfCells = row.getPhysicalNumberOfCells();

				//마지막 셀의 숫자 리턴
				numOfCells = row.getLastCellNum();

				/*
				 * 데이터를 담을 맵 객체 초기화
				 */
				map = new HashMap<String, String>();
				/*
				 * cell의 수 만큼 반복한다.
				 */
				for(int cellIndex = 0; cellIndex < numOfCells; cellIndex++) {
					/*
					 * Row에서 CellIndex에 해당하는 Cell을 가져온다.
					 */
					cell = row.getCell(cellIndex);
					/*
					 * 현재 Cell의 이름을 가져온다
					 * 이름의 예 : A,B,C,D,......
					 */
					cellName = getName(cell, cellIndex);
					/*
					 * 추출 대상 컬럼인지 확인한다
					 * 추출 대상 컬럼이 아니라면,
					 * for로 다시 올라간다
					 */
					if( !excelReadOption.getOutputColumns().contains(cellName) ) {
						continue;
					}
					/*
					 * map객체의 Cell의 이름을 키(Key)로 데이터를 담는다.
					 */
					map.put(cellName, getValue(cell));
				}
				//행번호 추가
				map.put("rowNum", String.valueOf(rowIndex+1));
				/*
				 * 만들어진 Map객체를 List로 넣는다.
				 */
				result.add(map);
			}
    	}
    	return result;
    }
}

 

3). Excel 파일을 읽을 때 옵션을 설정하는 java 파일을 만든다. <ExcelReadOption.java>

추가적으로 필요한 옵션을 설정해 줘도 좋다.

import java.util.ArrayList;
import java.util.List;

public class ExcelReadOption {

	//엑셀파일의 경로
	private String filePath;
	
	//추출할 컬럼명
	private List<String> outputColumns;
	
	//추출을 시작할 행 번호
	private int startRow;

	public String getFilePath() {
		return filePath;
	}

	public void setFilePath(String filePath) {
		this.filePath = filePath;
	}

	public List<String> getOutputColumns() {
		List<String> temp = new ArrayList<String>();
		temp.addAll(outputColumns);
		return temp;
	}

	public void setOutputColumns(List<String> outputColumns) {
		List<String> temp = new ArrayList<String>();
		temp.addAll(outputColumns);
		this.outputColumns = temp;
	}
	
	public void setOutputColumns(String ... outputColumns) {
		if(this.outputColumns == null) {
			this.outputColumns = new ArrayList<String>();
		}
        
		for(String ouputColumn : outputColumns) {
			this.outputColumns.add(ouputColumn);
		}
	}

	public int getStartRow() {
		return startRow;
	}

	public void setStartRow(int startRow) {
		this.startRow = startRow;
	}
	
	}

 

4). 사용코드

원하는 서비스로직에 추가해서 사용하면 될것같다.

MultipartHttpServletRequest multipart = (MultipartHttpServletRequest) req;
MultipartFile excelFile = multipart.getFile("excelFile");

//파일 저장후 읽어오자
//로컬 파일 저장 경로 => 내가 설정한 파일 경로를 사용하려고 한다.
String uploadRealPath = env.getProperty("excelFileTms.upload.realPath");

//엑셀파일을 읽기 위해서 서버에 저장
File destFile = new File(uploadRealPath + File.separator + "excel" + File.separator + excelFile.getOriginalFilename());
try{
	//경로가 없으면 경로생성
	if(!destFile.exists()) {
		destFile.mkdirs();
	}
	excelFile.transferTo(destFile);
}catch(Exception e){
	resultMap.put("result", Constant.XHR_REQUEST_FAIL);
	resultMap.put("msg", "Excel Upload Failed");
	return resultMap;
}

//엑셀 파일 읽기
ExcelReadOption excelReadOption = new ExcelReadOption();
excelReadOption.setFilePath(destFile.getAbsolutePath()); //파일경로 추가
excelReadOption.setOutputColumns("A","B","C","D","E","F","G","H","I","J","K","L","M"); //추출할 컬럼 설정
excelReadOption.setStartRow(2); //추출할 시작 행 설정
List<Map<String, String>> excelContent = ExcelUtil.excelRead(excelReadOption);

excelContent에 엑셀에서 내가 끄집어낸 데이터들이 담겨있으니 꺼내쓰면 끝

 

다음에는 다운로드를 만들어야지...

다운로드는 제약조건 걸어서 보내는 방법을 공부해보도록 하자...

반응형