Apache Jakarta의 하위 프로젝트 POI 싸이트(http://jakarta.apache.org/poi/)에서
api를 다운받는다. (현재 가능한 버전이 2004년 8월 4일 릴리즈된 2.5.1임)
1. poi 패키지 이용하여 읽기
import org.apache.poi.hssf.usermodel.*;
import java.io.*;
class ExcelTestRead
{
public static void main(String[] args)
{
try {
//입력 스트림 생성
FileInputStream fileInput = new FileInputStream("test.xls");
//Workbook 읽기
HSSFWorkbook workbook = new HSSFWorkbook(fileInput);
fileInput.close();
//Sheet 읽기
HSSFSheet sheet = workbook.getSheetAt(0);
//Row 읽기
HSSFRow row = sheet.getRow(0);
//Cell 3개 읽기
HSSFCell cell1 = row.getCell((short)0);
String string1 = cell1.getStringCellValue();
HSSFCell cell2 = row.getCell((short)1);
String string2 = cell2.getStringCellValue();
HSSFCell cell3 = row.getCell((short)2);
String string3 = cell3.getStringCellValue();
System.out.println("Excel File의 내용: "+string1+" | "+string2+" | "+string3);
}
catch(Exception e) {
System.out.println(e);
}
}
}
2. poi 패키지 이용하여 쓰기(java)
import org.apache.poi.hssf.usermodel.*;
import java.io.*;
class ExcelTestWrite
{
public static void main(String[] args)
{
try {
//Workbook 생성
HSSFWorkbook workbook = new HSSFWorkbook();
//Sheet를 생성
HSSFSheet sheet = workbook.createSheet("TEST SHEET");
//Row 생성
HSSFRow row = sheet.createRow(0);
//Cell 3개 생성
HSSFCell cell1 = row.createCell((short)0);
cell1.setCellValue("cell 1");
HSSFCell cell2 = row.createCell((short)1);
cell2.setCellValue("cell 2");
HSSFCell cell3 = row.createCell((short)2);
cell3.setCellValue("cell 3");
//파일로 쓰기
FileOutputStream fileOutput = new FileOutputStream("test.xls");
workbook.write(fileOutput);
fileOutput.close();
}
catch(Exception e) {
System.out.println(e);
}
}
}
3. poi 패키지 이용하여 쓰기(JSP/Servlet)
<%@ page language="java" contentType="application/vnd.ms-excel; name='excel', text/html; charset=UTF-8"
pageEncoding="UTF-8" errorPage="" %>
<%@ page import="org.w3c.dom.*"
%><%@ page import="com.inswave.util.*"
%><%@ page import="com.inswave.system.*"
%><%@ page import="org.apache.poi.hssf.util.*,org.apache.poi.hssf.usermodel.*,java.io.*,java.util.*"
%><%
HSSFWorkbook workbook = new HSSFWorkbook(); //workbook생성
HSSFSheet sheet = workbook.createSheet("총괄상환판"); //worksheet에 new sheet생성
OutputStream fileOut = response.getOutputStream();
try{
HSSFRow row = sheet.createRow(0);
HSSFCellStyle style = workbook.createCellStyle();
//style.setFillBackgroundColor(HSSFColor.ORANGE.index);
style.setFillForegroundColor(HSSFColor.YELLOW.index);
style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
HSSFCell cell;
cell = row.createCell((short)j);
cell.setCellValue(tit1[j]);
cell.setCellStyle(style);
workbook.write(fileOut);
} catch (Exception e){
throw e;
} finally {
if (fileOut != null) {
fileOut.close();
}
}
%>
//가로 병합
sheet.addMergedRegion(new Region(int 시작, short 시작col, int 종료row, short 종료col));
//세로 병합
sheet.addMergedRegion(new CellRangeAddress(first row, last row, first column, last column));
4. Html을 Excel 파일로 변환
<%@ page language="java" contentType="application/vnd.ms-excel; name='excel', text/html; charset=UTF-8"
pageEncoding="UTF-8" errorPage="" %>
<%
//EXCEL 파일명 지정
String filename = request.getParameter( "title" );
filename = new String(filename.getBytes("KSC5601"), "8859_1");
//response.setHeader("Content-Type", "application/vnd.ms-excel;charset=EUC-KR");
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename="+filename+".xls");
response.setHeader("Content-Description", "JSP Generated Data");
response.setHeader("Content-Transfer-Encoding", "binary;");
response.setHeader("Pragma", "no-cache;");
response.setHeader("Expires", "-1;");
out.clearBuffer();
%>
<style type="text/css">
td {font-family:돋움;}
</style>
<table>
<tr>
<td align="center">제목</td>
</tr>
<tr>
<td style='mso-number-format:"\@";'>0012122577</td>
</tr>
</table>
//한글깨짐
head 에 다음과 같은 처리를 같이 해주면 왠만하면 해결이 된다.
<META HTTP-EQUIVE="CONTENT-TYPE" CONTENT="TEXT/HTML; CHARSET=KSC5601">
or
엑셀 녀석이 데이터를 인코딩 태그로 인식하는 경우가 간혹 생기는데 데이터 타입 앞에 만 입력해주면 끝. 아주 깨끗하게 잘 나온다.
<td> <%= crset.getString(1) %></td> ← 이런 식으로
//숫자형식 엑셀에서 표현하기
<style type="text/css">
td {mso-number-format:000000;}
</style>
또는
<td align='center' style='mso-number-format:000000'>
000000 : 소수도 여섯자리 정수 (반올림)로 표현된다. 여섯자리 앞의 빈칸은 0으로 채워짐
1.23 => 000001, 67.67 => 000068
000.000 : 소수자리 세자리까지 (반올림) 표현된다. 앞 뒤 빈칸은 0으로 채워짐
format은 0.00 인데 숫자가 15.1 인 경우 15.10으로 표현됨
1.5678 => 001.568
\@ : 셀형식을 텍스트형으로 표현
00035.90 인 경우 셀 형식이 숫자형이라면 35.9로 표현되지만 문자형으로 하면 0을 포함하여 보이는 그대로 표현됨
//그 외 mso-number-format 요소들
NO Decimals
mso-number-format:"0\.000"
3 Decimals
mso-number-format:"\#\,\#\#0\.000"
Comma with 3 dec
mso-number-format:"mm\/dd\/yy"
Date7
mso-number-format:"mmmm\ d\,\ yyyy"
Date9
mso-number-format:"m\/d\/yy\ h\:mm\ AM\/PM"
D -T AMPM
mso-number-format:"Short Date"
01/03/1998
mso-number-format:"Medium Date"
01-mar-98
mso-number-format:"d\-mmm\-yyyy"
01-mar-1998
mso-number-format:"Short Time"
5:16
mso-number-format:"Medium Time"
5:16 am
mso-number-format:"Long Time"
5:16:21:00
mso-number-format:"Percent"
Percent - two decimals
mso-number-format:"0%"
Percent - no decimals
mso-number-format:"0\.E+00"
Scientific Notation
mso-number-format:"\@"
Text
mso-number-format:"\#\ ???\/???"
Fractions - up to 3 digits (312/943)
mso-number-format:"\0022£\0022\#\,\#\#0\.00"
£12.76
mso-number-format:"\#\,\#\#0\.00_ \;\[Red\]\-\#\,\#\#0\.00\"
2 decimals, negative numbers in red and signed(1.56 -1.56)
//한 셀 안에서 줄바꿈
<style>
.xl24 {mso-number-format:"\@";}
br {mso-data-placement:same-cell;}
</style>
JSP에서 excel 변환문제는 여러 포스트에서 볼수 있다.(나도 몰라서 쉽게 찾아서 했다.)
4. Spring MVC에서 jexcel 모듈을 활용한 엑셀 파일 다운로드
Spring MVC의 유연함을 확인할 수 있는 기능 중에 하나가 엑셀 다운로드와 같은 기능이리라. 지금까지 JSP 기반으로 UI를 서비스하다가 특정 기능에 대하여 엑셀로 다운로드하는 기능을 구현하고 싶다면 Spring MVC에서는 엑셀 다운로드를 담당하는 View를 만들어 교체해 주기만 하면 된다. 이전에 개발했던 비지니스 로직과 모델 API는 그대로 사용 가능하다. 물론 Spring MVC를 이용하지 않더라도 같은 기능을 구현할 수 있다. 하지만 Spring MVC를 이해하고 이 기반으로 엑셀 다운로드 기능을 구현하기란 정말 쉽다.
Spring MVC 3.0 기능에 대하여 먼저 공부하고 싶은 개발자가 있다면 최근에 공개된 Spring MVC 3 Showcase 문서를 참고한다. 동영상까지 제공하고 있으며, Spring MVC 3.0에서 제공하는 모든 기능을 예제 소스까지 포함하고 있어 Spring MVC 3.0을 공부하는 개발자에게 많은 도움이 되리라 생각한다.
먼저 엑셀 다운로드 기능을 구현하기 위하여 Controller를 다음과 같이 구현한다. 구현할 기능은 설문 결과를 엑셀로 다운로드 하는 기능이다.
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.View;
@Controller
@RequestMapping("/survey")
public class SurveyController {
@RequestMapping(value="/excel", method=RequestMethod.GET)
public View excel(ModelMap model) {
model.addAttribute("surveys", Survey.findAll(Survey.class));
return new SurveyExcelView();
}
}
위 예제 소스와 같이 설문 조사 결과를 Survey 클래스에서 조회한 후 ModelMap을 통하여 전달한다. 위와 같이 간단하게 Controller를 구현한 후 SurveyExcelView 클래스를 구현하면 된다.
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import org.springframework.web.servlet.view.document.AbstractJExcelView;
public class SurveyExcelView extends AbstractJExcelView {
protected void buildExcelDocument
(Map<String, Object> model, WritableWorkbook workbook, HttpServletRequest request,
HttpServletResponse response) throws Exception {
String fileName = createFileName();
setFileNameToResponse(request, response, fileName);
List<Survey> surveys = (List<Survey>)model.get("surveys");
WritableSheet sheet = workbook.createSheet("설문 목록", 0);
sheet.addCell(new jxl.write.Label(0, 0, "사용자아이디"));
for(int i=1; i < 13; i++) {
sheet.addCell(new jxl.write.Label(i, 0, "답변" + i));
}
int row = 1;
for (Iterator iterator = surveys.iterator(); iterator.hasNext();) {
Survey survey = (Survey) iterator.next();
sheet.addCell(new jxl.write.Label(0, row, survey.getUserId()));
sheet.addCell(new jxl.write.Number(1, row, survey.getAnswer1()));
sheet.addCell(new jxl.write.Number(2, row, survey.getAnswer2()));
sheet.addCell(new jxl.write.Label(3, row, survey.getAnswer3()));
sheet.addCell(new jxl.write.Number(4, row, survey.getAnswer4()));
row++;
}
}
private void setFileNameToResponse
(HttpServletRequest request, HttpServletResponse response, String fileName) {
String userAgent = request.getHeader("User-Agent");
if (userAgent.indexOf("MSIE 5.5") >= 0) {
response.setContentType("doesn/matter");
response.setHeader("Content-Disposition","filename=\""+fileName+"\"");
} else {
response.setHeader("Content-Disposition","attachment; filename=\""+fileName+"\"");
}
}
private String createFileName() {
SimpleDateFormat fileFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
return new StringBuilder("설문조사")
.append("-").append(fileFormat.format(new Date())).append(".xls").toString();
}
}
위와 같은 형태로 JExcel 기반으로 엑셀 파일을 생성한다. 위 예제 소스를 보면 알 수 있듯이 JExcel API를 이용하여 WritableWorkbook을 생성하고 엑셀 파일을 생성하는 부분은 모두 Spring 프레임워크에서 제공하는 AbstractJExcelView클래스가 담당하고 있다. 우리가 추가적으로 구현해야 할 부분은 WritableWorkbook API에 생성할 데이터를 추가하는 작업만 해주면 된다.
이와 같이 Spring MVC는 하나의 데이터를 여러 가지 View로 변환하는 작업을 어렵지 않게 할 수 있다. 앞으로 사용자가 엑셀 다운로드와 같은 기능을 요청하면 상당히 어려운 작업이라고 뻥치고 짧은 시간 내에 구현해 버려라. 이렇게 얻은 시간으로 다른 것을 공부하는데 투자하면 좋을 듯 하다.