(라이브러리) Jxls와 poi를 활용해서 엑셀다운로드 하기

청룡·2022년 3월 17일
0
post-thumbnail


프로젝트 셋업을 진행중, 엑셀 다운로드 기능이 있는 것을 보고 부랴부랴 검색해서 알아본 내용을 정리해본다.

sping maven 프로젝트로 진행했습니다.

maven 디펜더시를 추가해 줍니다.

<!-- XSSFWorkbook apache poi - Excel 2007 OOXML (.xlsx) 파일 포맷을 사용할 때 사용 -->
		<dependency>
		    <groupId>org.apache.poi</groupId>
		    <artifactId>poi-ooxml</artifactId>
		    <version>5.0.0</version>
		</dependency>
				
		
		<!-- HSSFWorkbook apache poi - Excel 97(-2007) 파일 포맷을 사용할 때 사용  -->
		<dependency>
		    <groupId>org.apache.poi</groupId>
		    <artifactId>poi</artifactId>
		    <version>5.0.0</version>
		</dependency>

		<!-- Excel Read/Write 를 위한 Dependency 추가 start-->
		<dependency>
			<groupId>org.jxls</groupId>
			<artifactId>jxls</artifactId>
			<version>2.10.0</version>
		</dependency>

		<dependency>
			<groupId>org.jxls</groupId>
			<artifactId>jxls-poi</artifactId>
			<version>2.10.0</version>
		</dependency>

		<dependency>
			<groupId>org.jxls</groupId>
			<artifactId>jxls-jexcel</artifactId>
			<version>1.0.8</version>
		</dependency>

다음과 같이 입력을 해서 추가해줍니다..... 이때!!! jxls의 버전에 주의하며 입력해줍니다. 왜냐하면 알아보니 1.x버전과 다른 점이 있다고 해서 한참 안되다가 jxls 문서에 나와있는 것을 활용하니 정상작동을 활용했습니다...

검색해도 안되면 문서가 역시 답... 영어를 언제 배워야하나...

우선 템플릿 없이 poi를 사용해서 엑셀 다운로드를 진행해보았다.

엑셀 다운로드는 따로 class를 생성해서 서블릿에서 요청하면 동작하도록 구현했다.

	@Override
	protected void renderMergedOutputModel(Map<String, Object> map, HttpServletRequest request, HttpServletResponse response) throws IOException {
		List<Map<String, Object>> dataList = (List<Map<String, Object>>) map.get("dataList");
		String sheetName = (String) map.get("sheetName");
		String fileName = (String) map.get("fileName");

		Iterator<String> keys = dataList.get(0).keySet().iterator();

		Workbook wb = new XSSFWorkbook();
		Sheet sheet = wb.createSheet(sheetName);
		Row row = null;
		Cell cell = null;
		int rowNum = 0;
		int cellNum = 0;

		//Header (셀이름)
		row = sheet.createRow(rowNum++);
		while(keys.hasNext()) {
			cell = row.createCell(cellNum++);
			cell.setCellValue(keys.next());
		}

		//Body (셀 값  한줄 한줄 반복문 쓸것)
		for(Map<String, Object> data : dataList) {
			row = sheet.createRow(rowNum++);
			int i = 0;
			for(String datakey : data.keySet()) {
				cell = row.createCell(i++);
				cell.setCellValue(data.get(datakey).toString());
			}
		}

		// 컨텐츠 타입 지정
		response.setContentType("ms-vnd/excel");
		fileName = new String(fileName.getBytes("KSC5601"), "8859_1");
		response.setHeader("Content-Disposition", "attachment;filename="+fileName+".xlsx");

		wb.write(response.getOutputStream());
		wb.close();
	}

다운로드 클래스에 AbstractView를 상속해서 페이지 이동이 되지 않고, 다운로드를 진행할수 있게했다.

필요한건 workbook과 sheet를 생성하고 이안에 값을 담아준다.

여기서 핵심은 받은 Map을 통해서 먼저 key를 통해서 헤드 행을 그린다음에 두번째 행부터는 값을 넣는 반복문을 돌렸다.

완료가 되었으면 response에 컨텐츠타입을 지정하고, 한글도 작성가능하도록 문자열을 변경시켜주고 workbook의 write()를 통해 내보내면 정상적으로 엑셀이 다운로드가 되었다.

참고로 서블릿에서 return 할때는 다음과 같이 지정해주면 된다.

return new ModelAndView(pv, data);

pv는 @Autowirde를 통해 가져온 JxlsExcelDownView이다. 물론 그전에 위 클래스를 component로 등록해야한다.


다음은 엑셀 템플릿을 활용한 방법입니다.

엑셀템플릿의 경우 장점은 서식을 적용할 수 있다는 점입니다. 그래서 date 타입 같은 경우 밀리세컨드초로 반환하게 되는데 이를 원하는 서식으로 지정해 놓으면 그 서식에 맞춰 값이 변화합니다.

@Component
public class JxlsExcelDownView extends AbstractView{

    @Override
    protected void renderMergedOutputModel(Map<String, Object> map, HttpServletRequest request, HttpServletResponse response) throws IOException {
        String template = (String) map.get("template");
        String newfileName = (String) map.get("newfileName");
        InputStream is = new ClassPathResource("/templates/" + template +".xlsx").getInputStream();
        String fileName = new String(newfileName.getBytes("KSC5601"), "8859_1");
        response.setContentType("ms-vnd/excel");
        response.setHeader("Content-Disposition", "attachment;filename="+fileName+".xlsx");
        Context context = new Context();
        context.putVar("data", map.get("data"));
        JxlsHelper.getInstance().processTemplate(is, response.getOutputStream(), context);
    }
}

jxls를 활용한 것은 템플릿을 사용하기 때문에 비교적 짧게 구현할 수 있었습니다

map에 필요한 정보들을 모두 가져온다음 Context에 data를 담고, jxlsHelper를 통해 비교적 간단하게 보낼 수 있습니다.

엑셀템플릿은 jstl el문과 비슷하게 작성할 수 있습니다. 핵심은 엑셀의 메모안에 필요한 jxls의 반복문 등을 수행하도록 할 수 있습니다.

위와같이 작성을 해주고 lastCell을 통해 영역을 지정해줍니다.
자세한 것은 jxls의 문서에서 확인부탁드립니다.

나중에 병합셀 같은 경우, 다양한 서식지정방법 등 jxls 문서를 통해 알아보는 시간을 가질 계획입니다.

추가적으로 서블릿에서 작성한 것도 공유드립니다. 여기서 jx와 po는 동일합니다

        @RequestMapping("/downbypoi")
        public ModelAndView excelDownload(HttpServletResponse response, HashMap<String,Object> params) throws Exception {

                List<HashMap<String, Object>> dataList = null;    // 데이터리스트를 넣으세요
                String sheetName = "테스트시트명";      // 엑셀 시트명을 입력해주세요
                String fileName = "test파일명123!@#_";  // 다운로드시 나타날 파일명을 입력해주세요

                Map<String, Object> data = new HashMap<>();
                data.put("dataList", dataList);
                data.put("sheetName", sheetName);
                data.put("fileName", fileName);

                return new ModelAndView(pv, data);
        }
profile
새대갈🕊️에서 돌고래🐬

0개의 댓글